fix: move storeRoles() to external JS with base layout inheritance
Some checks failed
Some checks failed
The inline storeRoles() was missing ...data() spread, causing Alpine errors for dark mode, sidebar, storeCode etc. Follow the same pattern as team.js: external JS file with ...data() and parent init() call. Uses apiClient and Utils.showToast per architecture rules. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -150,189 +150,5 @@
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_scripts %}
|
||||
<script>
|
||||
function storeRoles() {
|
||||
return {
|
||||
roles: [],
|
||||
loading: true,
|
||||
error: false,
|
||||
saving: false,
|
||||
showRoleModal: false,
|
||||
editingRole: null,
|
||||
roleForm: { name: '', permissions: [] },
|
||||
permissionsByCategory: {},
|
||||
presetRoles: ['manager', 'staff', 'support', 'viewer', 'marketing'],
|
||||
|
||||
async init() {
|
||||
await this.loadPermissions();
|
||||
await this.loadRoles();
|
||||
},
|
||||
|
||||
async loadPermissions() {
|
||||
try {
|
||||
const resp = await fetch(`/api/v1/store/team/me/permissions`, {
|
||||
headers: { 'Authorization': `Bearer ${this.getToken()}` }
|
||||
});
|
||||
// We need a permissions-by-category endpoint; for now use a simple list
|
||||
// Group known permissions by category prefix
|
||||
const allPerms = window.USER_PERMISSIONS || [];
|
||||
this.permissionsByCategory = this.groupPermissions(allPerms);
|
||||
} catch (e) {
|
||||
console.warn('Could not load permission categories:', e);
|
||||
}
|
||||
},
|
||||
|
||||
groupPermissions(permIds) {
|
||||
// Known permission categories from the codebase
|
||||
const knownPerms = [
|
||||
'dashboard.view',
|
||||
'settings.view', 'settings.edit', 'settings.theme', 'settings.domains',
|
||||
'products.view', 'products.create', 'products.edit', 'products.delete', 'products.import', 'products.export',
|
||||
'orders.view', 'orders.edit', 'orders.cancel', 'orders.refund',
|
||||
'customers.view', 'customers.edit', 'customers.delete', 'customers.export',
|
||||
'stock.view', 'stock.edit', 'stock.transfer',
|
||||
'team.view', 'team.invite', 'team.edit', 'team.remove',
|
||||
'analytics.view', 'analytics.export',
|
||||
'messaging.view_messages', 'messaging.send_messages', 'messaging.manage_templates',
|
||||
'billing.view_tiers', 'billing.manage_tiers', 'billing.view_subscriptions', 'billing.manage_subscriptions', 'billing.view_invoices',
|
||||
'cms.view_pages', 'cms.manage_pages', 'cms.view_media', 'cms.manage_media', 'cms.manage_themes',
|
||||
'loyalty.view_programs', 'loyalty.manage_programs', 'loyalty.view_rewards', 'loyalty.manage_rewards',
|
||||
'cart.view', 'cart.manage',
|
||||
];
|
||||
const groups = {};
|
||||
for (const perm of knownPerms) {
|
||||
const cat = perm.split('.')[0];
|
||||
if (!groups[cat]) groups[cat] = [];
|
||||
groups[cat].push({ id: perm });
|
||||
}
|
||||
return groups;
|
||||
},
|
||||
|
||||
async loadRoles() {
|
||||
this.loading = true;
|
||||
this.error = false;
|
||||
try {
|
||||
const resp = await fetch(`/api/v1/store/team/roles`, {
|
||||
headers: { 'Authorization': `Bearer ${this.getToken()}` }
|
||||
});
|
||||
if (!resp.ok) throw new Error('Failed to load roles');
|
||||
const data = await resp.json();
|
||||
this.roles = data.roles || [];
|
||||
} catch (e) {
|
||||
this.error = true;
|
||||
console.error('Error loading roles:', e);
|
||||
} finally {
|
||||
this.loading = false;
|
||||
}
|
||||
},
|
||||
|
||||
isPresetRole(name) {
|
||||
return this.presetRoles.includes(name.toLowerCase());
|
||||
},
|
||||
|
||||
openCreateModal() {
|
||||
this.editingRole = null;
|
||||
this.roleForm = { name: '', permissions: [] };
|
||||
this.showRoleModal = true;
|
||||
},
|
||||
|
||||
openEditModal(role) {
|
||||
this.editingRole = role;
|
||||
this.roleForm = {
|
||||
name: role.name,
|
||||
permissions: [...(role.permissions || [])],
|
||||
};
|
||||
this.showRoleModal = true;
|
||||
},
|
||||
|
||||
togglePermission(permId) {
|
||||
const idx = this.roleForm.permissions.indexOf(permId);
|
||||
if (idx >= 0) {
|
||||
this.roleForm.permissions.splice(idx, 1);
|
||||
} else {
|
||||
this.roleForm.permissions.push(permId);
|
||||
}
|
||||
},
|
||||
|
||||
toggleCategory(category) {
|
||||
const perms = this.permissionsByCategory[category] || [];
|
||||
const permIds = perms.map(p => p.id);
|
||||
const allSelected = permIds.every(id => this.roleForm.permissions.includes(id));
|
||||
if (allSelected) {
|
||||
this.roleForm.permissions = this.roleForm.permissions.filter(id => !permIds.includes(id));
|
||||
} else {
|
||||
for (const id of permIds) {
|
||||
if (!this.roleForm.permissions.includes(id)) {
|
||||
this.roleForm.permissions.push(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
isCategoryFullySelected(category) {
|
||||
const perms = this.permissionsByCategory[category] || [];
|
||||
return perms.length > 0 && perms.every(p => this.roleForm.permissions.includes(p.id));
|
||||
},
|
||||
|
||||
async saveRole() {
|
||||
this.saving = true;
|
||||
try {
|
||||
const url = this.editingRole
|
||||
? `/api/v1/store/team/roles/${this.editingRole.id}`
|
||||
: '/api/v1/store/team/roles';
|
||||
const method = this.editingRole ? 'PUT' : 'POST';
|
||||
|
||||
const resp = await fetch(url, {
|
||||
method,
|
||||
headers: {
|
||||
'Authorization': `Bearer ${this.getToken()}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(this.roleForm),
|
||||
});
|
||||
|
||||
if (!resp.ok) {
|
||||
const err = await resp.json();
|
||||
alert(err.detail || 'Failed to save role');
|
||||
return;
|
||||
}
|
||||
|
||||
this.showRoleModal = false;
|
||||
await this.loadRoles();
|
||||
} catch (e) {
|
||||
console.error('Error saving role:', e);
|
||||
alert('Failed to save role');
|
||||
} finally {
|
||||
this.saving = false;
|
||||
}
|
||||
},
|
||||
|
||||
async confirmDelete(role) {
|
||||
if (!confirm(`Delete role "${role.name}"? This cannot be undone.`)) return;
|
||||
try {
|
||||
const resp = await fetch(`/api/v1/store/team/roles/${role.id}`, {
|
||||
method: 'DELETE',
|
||||
headers: { 'Authorization': `Bearer ${this.getToken()}` },
|
||||
});
|
||||
if (!resp.ok) {
|
||||
const err = await resp.json();
|
||||
alert(err.detail || 'Failed to delete role');
|
||||
return;
|
||||
}
|
||||
await this.loadRoles();
|
||||
} catch (e) {
|
||||
console.error('Error deleting role:', e);
|
||||
alert('Failed to delete role');
|
||||
}
|
||||
},
|
||||
|
||||
getToken() {
|
||||
return document.cookie.split(';')
|
||||
.map(c => c.trim())
|
||||
.find(c => c.startsWith('store_token='))
|
||||
?.split('=')[1] || '';
|
||||
},
|
||||
};
|
||||
}
|
||||
</script>
|
||||
<script defer src="{{ url_for('tenancy_static', path='store/js/roles.js') }}"></script>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user