// static/vendor/js/team.js /** * Vendor team management page logic * Manage team members, invitations, and roles */ const vendorTeamLog = window.LogConfig.loggers.vendorTeam || window.LogConfig.createLogger('vendorTeam', false); vendorTeamLog.info('Loading...'); function vendorTeam() { vendorTeamLog.info('vendorTeam() called'); return { // Inherit base layout state ...data(), // Set page identifier currentPage: 'team', // Loading states loading: true, error: '', saving: false, // Team data members: [], roles: [], stats: { total: 0, active_count: 0, pending_invitations: 0 }, // Modal states showInviteModal: false, showEditModal: false, showRemoveModal: false, selectedMember: null, // Invite form inviteForm: { email: '', first_name: '', last_name: '', role_name: 'staff' }, // Edit form editForm: { role_id: null, is_active: true }, // Available role names for invite roleOptions: [ { value: 'owner', label: 'Owner', description: 'Full access to all features' }, { value: 'manager', label: 'Manager', description: 'Manage orders, products, and team' }, { value: 'staff', label: 'Staff', description: 'Handle orders and products' }, { value: 'support', label: 'Support', description: 'Customer support access' }, { value: 'viewer', label: 'Viewer', description: 'Read-only access' }, { value: 'marketing', label: 'Marketing', description: 'Content and promotions' } ], async init() { vendorTeamLog.info('Team init() called'); // Guard against multiple initialization if (window._vendorTeamInitialized) { vendorTeamLog.warn('Already initialized, skipping'); return; } window._vendorTeamInitialized = true; // IMPORTANT: Call parent init first to set vendorCode from URL const parentInit = data().init; if (parentInit) { await parentInit.call(this); } try { await Promise.all([ this.loadMembers(), this.loadRoles() ]); } catch (error) { vendorTeamLog.error('Init failed:', error); this.error = 'Failed to initialize team page'; } vendorTeamLog.info('Team initialization complete'); }, /** * Load team members */ async loadMembers() { this.loading = true; this.error = ''; try { const response = await apiClient.get(`/vendor/team/members?include_inactive=true`); this.members = response.members || []; this.stats = { total: response.total || 0, active_count: response.active_count || 0, pending_invitations: response.pending_invitations || 0 }; vendorTeamLog.info('Loaded team members:', this.members.length); } catch (error) { vendorTeamLog.error('Failed to load team members:', error); this.error = error.message || 'Failed to load team members'; } finally { this.loading = false; } }, /** * Load available roles */ async loadRoles() { try { const response = await apiClient.get(`/vendor/team/roles`); this.roles = response.roles || []; vendorTeamLog.info('Loaded roles:', this.roles.length); } catch (error) { vendorTeamLog.error('Failed to load roles:', error); } }, /** * Open invite modal */ openInviteModal() { this.inviteForm = { email: '', first_name: '', last_name: '', role_name: 'staff' }; this.showInviteModal = true; }, /** * Send invitation */ async sendInvitation() { if (!this.inviteForm.email) { Utils.showToast('Email is required', 'error'); return; } this.saving = true; try { await apiClient.post(`/vendor/team/invite`, this.inviteForm); Utils.showToast('Invitation sent successfully', 'success'); vendorTeamLog.info('Invitation sent to:', this.inviteForm.email); this.showInviteModal = false; await this.loadMembers(); } catch (error) { vendorTeamLog.error('Failed to send invitation:', error); Utils.showToast(error.message || 'Failed to send invitation', 'error'); } finally { this.saving = false; } }, /** * Open edit member modal */ openEditModal(member) { this.selectedMember = member; this.editForm = { role_id: member.role_id, is_active: member.is_active }; this.showEditModal = true; }, /** * Update team member */ async updateMember() { if (!this.selectedMember) return; this.saving = true; try { await apiClient.put( `/vendor/${this.vendorCode}/team/members/${this.selectedMember.user_id}`, this.editForm ); Utils.showToast('Team member updated', 'success'); vendorTeamLog.info('Updated team member:', this.selectedMember.user_id); this.showEditModal = false; this.selectedMember = null; await this.loadMembers(); } catch (error) { vendorTeamLog.error('Failed to update team member:', error); Utils.showToast(error.message || 'Failed to update team member', 'error'); } finally { this.saving = false; } }, /** * Confirm remove member */ confirmRemove(member) { this.selectedMember = member; this.showRemoveModal = true; }, /** * Remove team member */ async removeMember() { if (!this.selectedMember) return; this.saving = true; try { await apiClient.delete(`/vendor/team/members/${this.selectedMember.user_id}`); Utils.showToast('Team member removed', 'success'); vendorTeamLog.info('Removed team member:', this.selectedMember.user_id); this.showRemoveModal = false; this.selectedMember = null; await this.loadMembers(); } catch (error) { vendorTeamLog.error('Failed to remove team member:', error); Utils.showToast(error.message || 'Failed to remove team member', 'error'); } finally { this.saving = false; } }, /** * Get role display name */ getRoleName(member) { if (member.role_name) return member.role_name; const role = this.roles.find(r => r.id === member.role_id); return role ? role.name : 'Unknown'; }, /** * Get member initials for avatar */ getInitials(member) { const first = member.first_name || member.email?.charAt(0) || ''; const last = member.last_name || ''; return (first.charAt(0) + last.charAt(0)).toUpperCase() || '?'; }, /** * Format date for display */ formatDate(dateStr) { if (!dateStr) return '-'; const locale = window.VENDOR_CONFIG?.locale || 'en-GB'; return new Date(dateStr).toLocaleDateString(locale, { year: 'numeric', month: 'short', day: 'numeric' }); } }; }