diff --git a/.env.development b/.env.development
new file mode 100644
index 0000000..6ec835a
--- /dev/null
+++ b/.env.development
@@ -0,0 +1,3 @@
+REACT_APP_BACKEND_URL=http://localhost:8000
+REACT_APP_BASENAME=/membership
+PUBLIC_URL=/membership
diff --git a/src/components/InviteStaffDialog.js b/src/components/InviteStaffDialog.js
index b15d4ae..97e9252 100644
--- a/src/components/InviteStaffDialog.js
+++ b/src/components/InviteStaffDialog.js
@@ -40,15 +40,14 @@ const InviteStaffDialog = ({ open, onOpenChange, onSuccess }) => {
const fetchRoles = async () => {
setLoadingRoles(true);
try {
- const response = await api.get('/admin/roles');
- // Filter to show only admin-type roles (not guest or member)
- const staffRoles = response.data.filter(role =>
- ['admin', 'superadmin', 'finance'].includes(role.code) || !role.is_system_role
- );
- setRoles(staffRoles);
+ // New endpoint returns roles based on user's permission level
+ // Superadmin: all roles
+ // Admin: admin, finance, and non-elevated custom roles
+ const response = await api.get('/admin/roles/assignable');
+ setRoles(response.data);
} catch (error) {
- console.error('Failed to fetch roles:', error);
- toast.error('Failed to load roles');
+ console.error('Failed to fetch assignable roles:', error);
+ toast.error('Failed to load roles. Please try again.');
} finally {
setLoadingRoles(false);
}
diff --git a/src/pages/admin/AdminBylaws.js b/src/pages/admin/AdminBylaws.js
index e66ece4..54f07df 100644
--- a/src/pages/admin/AdminBylaws.js
+++ b/src/pages/admin/AdminBylaws.js
@@ -1,4 +1,5 @@
import React, { useEffect, useState } from 'react';
+import { useAuth } from '../../context/AuthContext';
import api from '../../utils/api';
import { Card } from '../../components/ui/card';
import { Button } from '../../components/ui/button';
@@ -32,6 +33,7 @@ import {
} from 'lucide-react';
const AdminBylaws = () => {
+ const { hasPermission } = useAuth();
const [bylaws, setBylaws] = useState([]);
const [loading, setLoading] = useState(true);
const [dialogOpen, setDialogOpen] = useState(false);
@@ -184,13 +186,15 @@ const AdminBylaws = () => {
Manage LOAF governing bylaws and version history
-
+ {hasPermission('bylaws.create') && (
+
+ )}
{/* Current Bylaws */}
@@ -226,22 +230,26 @@ const AdminBylaws = () => {
View
-
-
+ {hasPermission('bylaws.edit') && (
+
+ )}
+ {hasPermission('bylaws.delete') && (
+
+ )}
@@ -254,10 +262,12 @@ const AdminBylaws = () => {
No current bylaws set
-
+ {hasPermission('bylaws.create') && (
+
+ )}
)}
@@ -290,22 +300,26 @@ const AdminBylaws = () => {
>
-
-
+ {hasPermission('bylaws.edit') && (
+
+ )}
+ {hasPermission('bylaws.delete') && (
+
+ )}
diff --git a/src/pages/admin/AdminDonations.js b/src/pages/admin/AdminDonations.js
index 6ac6bc6..4bf773f 100644
--- a/src/pages/admin/AdminDonations.js
+++ b/src/pages/admin/AdminDonations.js
@@ -1,4 +1,5 @@
import React, { useState, useEffect } from 'react';
+import { useAuth } from '../../context/AuthContext';
import { Card } from '../../components/ui/card';
import { Button } from '../../components/ui/button';
import { Input } from '../../components/ui/input';
@@ -31,6 +32,7 @@ import {
} from 'lucide-react';
const AdminDonations = () => {
+ const { hasPermission } = useAuth();
const [donations, setDonations] = useState([]);
const [filteredDonations, setFilteredDonations] = useState([]);
const [stats, setStats] = useState({});
@@ -269,33 +271,35 @@ const AdminDonations = () => {
className="pl-10 rounded-full border-2 border-[#ddd8eb] focus:border-[#664fa3]"
/>
-
-
-
-
-
- handleExport('all')}
- className="cursor-pointer hover:bg-[#f1eef9] rounded-lg p-3"
- >
-
- Export All Donations
-
- handleExport('current')}
- className="cursor-pointer hover:bg-[#f1eef9] rounded-lg p-3"
- >
-
- Export Current View
-
-
-
+ {hasPermission('donations.export') && (
+
+
+
+
+
+ handleExport('all')}
+ className="cursor-pointer hover:bg-[#f1eef9] rounded-lg p-3"
+ >
+
+ Export All Donations
+
+ handleExport('current')}
+ className="cursor-pointer hover:bg-[#f1eef9] rounded-lg p-3"
+ >
+
+ Export Current View
+
+
+
+ )}
{/* Filters Row */}
diff --git a/src/pages/admin/AdminFinancials.js b/src/pages/admin/AdminFinancials.js
index e79a2b7..6669e59 100644
--- a/src/pages/admin/AdminFinancials.js
+++ b/src/pages/admin/AdminFinancials.js
@@ -1,4 +1,5 @@
import React, { useEffect, useState } from 'react';
+import { useAuth } from '../../context/AuthContext';
import api from '../../utils/api';
import { Card } from '../../components/ui/card';
import { Button } from '../../components/ui/button';
@@ -31,6 +32,7 @@ import {
} from 'lucide-react';
const AdminFinancials = () => {
+ const { hasPermission } = useAuth();
const [reports, setReports] = useState([]);
const [loading, setLoading] = useState(true);
const [dialogOpen, setDialogOpen] = useState(false);
@@ -162,13 +164,15 @@ const AdminFinancials = () => {
Manage annual financial reports
-
+ {hasPermission('financials.create') && (
+
+ )}
{/* Reports List */}
@@ -176,10 +180,12 @@ const AdminFinancials = () => {
No financial reports yet
-
+ {hasPermission('financials.create') && (
+
+ )}
) : (
@@ -209,24 +215,30 @@ const AdminFinancials = () => {
-
-
-
-
+ {(hasPermission('financials.edit') || hasPermission('financials.delete')) && (
+
+ {hasPermission('financials.edit') && (
+
+ )}
+ {hasPermission('financials.delete') && (
+
+ )}
+
+ )}
))}
diff --git a/src/pages/admin/AdminGallery.js b/src/pages/admin/AdminGallery.js
index e7aac7d..173570e 100644
--- a/src/pages/admin/AdminGallery.js
+++ b/src/pages/admin/AdminGallery.js
@@ -1,5 +1,6 @@
import React, { useState, useEffect, useRef } from 'react';
import { Link } from 'react-router-dom';
+import { useAuth } from '../../context/AuthContext';
import api from '../../utils/api';
import { Card } from '../../components/ui/card';
import { Button } from '../../components/ui/button';
@@ -20,6 +21,7 @@ import { toast } from 'sonner';
import moment from 'moment';
const AdminGallery = () => {
+ const { hasPermission } = useAuth();
const [events, setEvents] = useState([]);
const [selectedEvent, setSelectedEvent] = useState(null);
const [galleryImages, setGalleryImages] = useState([]);
@@ -206,7 +208,7 @@ const AdminGallery = () => {
)}
- {selectedEvent && (
+ {selectedEvent && hasPermission('gallery.upload') && (
{
{/* Overlay with Actions */}
-
-
-
-
+ {(hasPermission('gallery.edit') || hasPermission('gallery.delete')) && (
+
+ {hasPermission('gallery.edit') && (
+
+ )}
+ {hasPermission('gallery.delete') && (
+
+ )}
+
+ )}
{/* Caption Preview */}
{image.caption && (
diff --git a/src/pages/admin/AdminNewsletters.js b/src/pages/admin/AdminNewsletters.js
index e6d807b..64ac9f5 100644
--- a/src/pages/admin/AdminNewsletters.js
+++ b/src/pages/admin/AdminNewsletters.js
@@ -1,4 +1,5 @@
import React, { useEffect, useState } from 'react';
+import { useAuth } from '../../context/AuthContext';
import api from '../../utils/api';
import { Card } from '../../components/ui/card';
import { Button } from '../../components/ui/button';
@@ -32,6 +33,7 @@ import {
} from 'lucide-react';
const AdminNewsletters = () => {
+ const { hasPermission } = useAuth();
const [newsletters, setNewsletters] = useState([]);
const [loading, setLoading] = useState(true);
const [dialogOpen, setDialogOpen] = useState(false);
@@ -190,13 +192,15 @@ const AdminNewsletters = () => {
Create and manage newsletter archive
-
+ {hasPermission('newsletters.create') && (
+
+ )}
{/* Newsletters List */}
@@ -204,10 +208,12 @@ const AdminNewsletters = () => {
No newsletters yet
-
+ {hasPermission('newsletters.create') && (
+
+ )}
) : (
@@ -246,24 +252,30 @@ const AdminNewsletters = () => {
-
-
-
-
+ {(hasPermission('newsletters.edit') || hasPermission('newsletters.delete')) && (
+
+ {hasPermission('newsletters.edit') && (
+
+ )}
+ {hasPermission('newsletters.delete') && (
+
+ )}
+
+ )}
))}
diff --git a/src/pages/admin/AdminPlans.js b/src/pages/admin/AdminPlans.js
index 1a6e5c0..439f75a 100644
--- a/src/pages/admin/AdminPlans.js
+++ b/src/pages/admin/AdminPlans.js
@@ -1,4 +1,5 @@
import React, { useEffect, useState } from 'react';
+import { useAuth } from '../../context/AuthContext';
import api from '../../utils/api';
import { Card } from '../../components/ui/card';
import { Button } from '../../components/ui/button';
@@ -24,6 +25,7 @@ import {
} from 'lucide-react';
const AdminPlans = () => {
+ const { hasPermission } = useAuth();
const [plans, setPlans] = useState([]);
const [filteredPlans, setFilteredPlans] = useState([]);
const [loading, setLoading] = useState(true);
@@ -136,13 +138,15 @@ const AdminPlans = () => {
Manage membership plans and pricing.
-
+ {hasPermission('subscriptions.plans') && (
+
+ )}
@@ -286,27 +290,29 @@ const AdminPlans = () => {
{/* Actions */}
-
-
-
-
+ {hasPermission('subscriptions.plans') && (
+
+
+
+
+ )}
{/* Warning for plans with subscribers */}
{plan.subscriber_count > 0 && (
@@ -328,7 +334,7 @@ const AdminPlans = () => {
? 'Try adjusting your filters'
: 'Create your first subscription plan to get started'}
- {!searchQuery && activeFilter === 'all' && (
+ {!searchQuery && activeFilter === 'all' && hasPermission('subscriptions.plans') && (