Marketing Hub: RBAC, i18n (AR/EN), tasks overhaul, team/user merge, tutorial
Features: - Full RBAC with 3 roles (superadmin/manager/contributor) - Ownership tracking on posts, tasks, campaigns, projects - Task system: assign to anyone, filter combobox, visibility scoping - Team members merged into users table (single source of truth) - Post thumbnails on kanban cards from attachments - Publication link validation before publishing - Interactive onboarding tutorial with Settings restart - Full Arabic/English i18n with RTL layout support - Language toggle in sidebar, IBM Plex Sans Arabic font - Brand-based visibility filtering for non-superadmins - Manager can only create contributors - Profile completion flow for new users - Cookie-based sessions (express-session + SQLite)
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
import BrandBadge from './BrandBadge'
|
||||
|
||||
const ROLE_BADGES = {
|
||||
manager: { bg: 'bg-indigo-50', text: 'text-indigo-700', label: 'Manager' },
|
||||
approver: { bg: 'bg-emerald-50', text: 'text-emerald-700', label: 'Approver' },
|
||||
publisher: { bg: 'bg-blue-50', text: 'text-blue-700', label: 'Publisher' },
|
||||
content_creator: { bg: 'bg-amber-50', text: 'text-amber-700', label: 'Content Creator' },
|
||||
producer: { bg: 'bg-purple-50', text: 'text-purple-700', label: 'Producer' },
|
||||
designer: { bg: 'bg-pink-50', text: 'text-pink-700', label: 'Designer' },
|
||||
content_writer: { bg: 'bg-orange-50', text: 'text-orange-700', label: 'Content Writer' },
|
||||
social_media_manager: { bg: 'bg-teal-50', text: 'text-teal-700', label: 'Social Media Manager' },
|
||||
photographer: { bg: 'bg-cyan-50', text: 'text-cyan-700', label: 'Photographer' },
|
||||
videographer: { bg: 'bg-sky-50', text: 'text-sky-700', label: 'Videographer' },
|
||||
strategist: { bg: 'bg-rose-50', text: 'text-rose-700', label: 'Strategist' },
|
||||
default: { bg: 'bg-gray-50', text: 'text-gray-700', label: 'Team Member' },
|
||||
}
|
||||
|
||||
export default function MemberCard({ member, onClick }) {
|
||||
const getInitials = (name) => {
|
||||
if (!name) return '?'
|
||||
return name.split(' ').map(w => w[0]).join('').slice(0, 2).toUpperCase()
|
||||
}
|
||||
|
||||
const role = ROLE_BADGES[member.team_role || member.role] || ROLE_BADGES.default
|
||||
|
||||
const avatarColors = [
|
||||
'from-indigo-400 to-purple-500',
|
||||
'from-pink-400 to-rose-500',
|
||||
'from-emerald-400 to-teal-500',
|
||||
'from-amber-400 to-orange-500',
|
||||
'from-cyan-400 to-blue-500',
|
||||
]
|
||||
const colorIndex = (member.name?.charCodeAt(0) || 0) % avatarColors.length
|
||||
|
||||
return (
|
||||
<div
|
||||
onClick={() => onClick?.(member)}
|
||||
className="bg-white rounded-xl border border-border p-5 card-hover cursor-pointer text-center"
|
||||
>
|
||||
{/* Avatar */}
|
||||
<div className={`w-16 h-16 rounded-full bg-gradient-to-br ${avatarColors[colorIndex]} flex items-center justify-center text-white text-xl font-bold mx-auto mb-3`}>
|
||||
{getInitials(member.name)}
|
||||
</div>
|
||||
|
||||
{/* Name */}
|
||||
<h4 className="text-base font-semibold text-text-primary">{member.name}</h4>
|
||||
|
||||
{/* Role badge */}
|
||||
<span className={`inline-block text-xs font-medium px-2 py-0.5 rounded-full mt-1 ${role.bg} ${role.text}`}>
|
||||
{role.label}
|
||||
</span>
|
||||
|
||||
{/* Email */}
|
||||
{member.email && (
|
||||
<p className="text-xs text-text-tertiary mt-2">{member.email}</p>
|
||||
)}
|
||||
|
||||
{/* Brands */}
|
||||
{member.brands && member.brands.length > 0 && (
|
||||
<div className="flex flex-wrap gap-1 justify-center mt-3 pt-3 border-t border-border-light">
|
||||
{member.brands.map((brand) => (
|
||||
<BrandBadge key={brand} brand={brand} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user