File size: 5,882 Bytes
766d85d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
import { useState, useEffect } from 'react'
import { createPortal } from 'react-dom'
import { useNavigate } from 'react-router-dom'
import { useAuthStore } from '../../store/authStore'
import { useInAppNotificationStore } from '../../store/inAppNotificationStore'
import { useTranslation } from '../../i18n'
import { Bell, Settings, Shield, LogOut } from 'lucide-react'

// Mobile-only: a slim strip at the very top of the dashboard with the
// notification + profile icons (right-aligned). Scrolls with the page.
export default function MobileTopBar() {
  const { t } = useTranslation()
  const navigate = useNavigate()
  const { user, isAuthenticated } = useAuthStore()
  const unread = useInAppNotificationStore(s => s.unreadCount)
  const fetchUnreadCount = useInAppNotificationStore(s => s.fetchUnreadCount)
  const [showProfile, setShowProfile] = useState(false)

  useEffect(() => { if (isAuthenticated) fetchUnreadCount() }, [isAuthenticated])

  return (
    <>
      <div
        className="md:hidden flex items-center justify-end gap-2 px-4"
        style={{ paddingTop: 'calc(10px + env(safe-area-inset-top, 0px))', paddingBottom: 10 }}
      >
        <button
          onClick={() => navigate('/notifications')}
          aria-label={t('notifications.title')}
          className="relative grid place-items-center rounded-full active:scale-95 transition-transform"
          style={{ width: 36, height: 36, color: 'var(--ink-2, #52525b)' }}
        >
          <Bell size={20} strokeWidth={1.9} />
          {unread > 0 && (
            <span style={{ position: 'absolute', top: 7, right: 7, width: 8, height: 8, borderRadius: '50%', background: 'oklch(0.7 0.17 38)', boxShadow: '0 0 0 2px var(--bg, #fff)' }} />
          )}
        </button>
        <button
          onClick={() => setShowProfile(true)}
          aria-label={t('nav.profile')}
          className="grid place-items-center rounded-full text-white font-semibold text-[12px] active:scale-95 transition-transform"
          style={{ width: 34, height: 34, background: 'linear-gradient(135deg, oklch(0.7 0.14 38), oklch(0.55 0.13 25))' }}
        >
          {(user?.username || '?')[0].toUpperCase()}
        </button>
      </div>

      {showProfile && createPortal(<ProfileSheet onClose={() => setShowProfile(false)} />, document.body)}
    </>
  )
}

function ProfileSheet({ onClose }: { onClose: () => void }) {
  const { t } = useTranslation()
  const { user, logout } = useAuthStore()
  const navigate = useNavigate()

  const handleNav = (path: string) => { onClose(); navigate(path) }
  const handleLogout = () => { onClose(); logout(); navigate('/login') }

  return (
    <div className="fixed inset-0 z-[300] md:hidden" onClick={onClose}>
      <div className="absolute inset-0 bg-black/50 backdrop-blur-sm" />
      <div
        className="absolute bottom-0 left-0 right-0 bg-white dark:bg-zinc-900 rounded-t-2xl overflow-hidden"
        style={{ animation: 'slideUp 0.25s ease-out', paddingBottom: 'env(safe-area-inset-bottom, 0px)' }}
        onClick={e => e.stopPropagation()}
      >
        <div className="flex justify-center pt-3 pb-2">
          <div className="w-10 h-1 rounded-full bg-zinc-300 dark:bg-zinc-700" />
        </div>

        <div className="px-6 pb-4 pt-1">
          <div className="flex items-center gap-3">
            <div className="w-11 h-11 rounded-full bg-zinc-900 dark:bg-white text-white dark:text-zinc-900 flex items-center justify-center text-[16px] font-bold">
              {(user?.username || '?')[0].toUpperCase()}
            </div>
            <div className="flex-1 min-w-0">
              <p className="text-[15px] font-semibold text-zinc-900 dark:text-white">{user?.username}</p>
              <p className="text-[12px] text-zinc-500 truncate">{user?.email}</p>
            </div>
            {user?.role === 'admin' && (
              <span className="flex items-center gap-1 px-2 py-0.5 rounded-full bg-zinc-100 dark:bg-zinc-800 text-[10px] font-semibold text-zinc-600 dark:text-zinc-400 uppercase tracking-wide">
                <Shield size={10} /> Admin
              </span>
            )}
          </div>
        </div>

        <div className="h-px bg-zinc-100 dark:bg-zinc-800 mx-4" />

        <div className="py-2 px-2">
          <button
            onClick={() => handleNav('/settings')}
            className="w-full flex items-center gap-3 px-4 py-3 rounded-xl text-left hover:bg-zinc-50 dark:hover:bg-zinc-800 active:bg-zinc-100 dark:active:bg-zinc-800 transition-colors"
          >
            <Settings size={18} className="text-zinc-500" />
            <span className="text-[14px] font-medium text-zinc-900 dark:text-white">{t('nav.bottomSettings')}</span>
          </button>

          {user?.role === 'admin' && (
            <button
              onClick={() => handleNav('/admin')}
              className="w-full flex items-center gap-3 px-4 py-3 rounded-xl text-left hover:bg-zinc-50 dark:hover:bg-zinc-800 active:bg-zinc-100 dark:active:bg-zinc-800 transition-colors"
            >
              <Shield size={18} className="text-zinc-500" />
              <span className="text-[14px] font-medium text-zinc-900 dark:text-white">{t('nav.bottomAdmin')}</span>
            </button>
          )}
        </div>

        <div className="h-px bg-zinc-100 dark:bg-zinc-800 mx-4" />

        <div className="py-2 px-2">
          <button
            onClick={handleLogout}
            className="w-full flex items-center gap-3 px-4 py-3 rounded-xl text-left hover:bg-red-50 dark:hover:bg-red-900/20 active:bg-red-100 transition-colors"
          >
            <LogOut size={18} className="text-red-500" />
            <span className="text-[14px] font-medium text-red-600 dark:text-red-400">{t('nav.bottomLogout')}</span>
          </button>
        </div>

        <div className="h-4" />
      </div>
    </div>
  )
}