diff --git a/guardian-admin-dashboard/src/pages/OrgAssignmentPage.jsx b/guardian-admin-dashboard/src/pages/OrgAssignmentPage.jsx index 2f5587c80..37a33f2f2 100644 --- a/guardian-admin-dashboard/src/pages/OrgAssignmentPage.jsx +++ b/guardian-admin-dashboard/src/pages/OrgAssignmentPage.jsx @@ -13,14 +13,19 @@ import { import { Link } from "react-router-dom"; import Button from "../components/common/Button"; import Dropdown from "../components/common/Dropdown"; -import { getMyOrganizations } from "../services/orgService"; +import OrgDetailPage from './OrgDetailPage'; +import { getOrganizations, createOrganization } from "../services/orgService"; + +const initialFormData = { + name: '', + description: '', + active: 'true', +}; function formatDate(dateValue) { if (!dateValue) return "-"; - const date = new Date(dateValue); if (Number.isNaN(date.getTime())) return "-"; - return date.toLocaleDateString("en-AU", { day: "2-digit", month: "short", @@ -33,15 +38,20 @@ export default function OrgAssignmentPage() { const [selectedOrgId, setSelectedOrgId] = useState(""); const [loading, setLoading] = useState(true); const [error, setError] = useState(""); + const [selectedViewOrg, setSelectedViewOrg] = useState(null); + + const [showForm, setShowForm] = useState(false); + const [formData, setFormData] = useState(initialFormData); + const [submitting, setSubmitting] = useState(false); + const [formError, setFormError] = useState(''); + const [successMessage, setSuccessMessage] = useState(''); const fetchOrganizations = useCallback(async () => { setLoading(true); setError(""); - try { - const response = await getMyOrganizations(); + const response = await getOrganizations(); const orgs = Array.isArray(response?.orgs) ? response.orgs : []; - setOrganizations(orgs); setSelectedOrgId((prev) => prev || orgs[0]?._id || ""); } catch (err) { @@ -64,28 +74,58 @@ export default function OrgAssignmentPage() { label: org.name, })); - const stats = selectedOrg - ? [ - { - title: "Staff Members", - value: selectedOrg.staff?.length ?? 0, - icon: Users, - description: "Staff currently linked with this organisation.", - }, - { - title: "Status", - value: selectedOrg.active ? "Active" : "Inactive", - icon: ShieldCheck, - description: "Current organisation status from backend data.", - }, - { - title: "Created On", - value: formatDate(selectedOrg.created_at), - icon: CalendarDays, - description: "Date this organisation record was created.", - }, - ] - : []; + const handleInputChange = (e) => { + const { name, value } = e.target; + setFormData((prev) => ({ ...prev, [name]: value })); + }; + + const resetForm = () => { + setFormData(initialFormData); + }; + + const handleToggleForm = () => { + setShowForm((prev) => !prev); + setFormError(''); + setSuccessMessage(''); + if (showForm) resetForm(); + }; + + const handleAddOrganization = async (e) => { + e.preventDefault(); + + if (!formData.name || !formData.description) { + setFormError('Name and description are required.'); + setSuccessMessage(''); + return; + } + + try { + setSubmitting(true); + setFormError(''); + setSuccessMessage(''); + + const payload = { + name: formData.name, + description: formData.description, + active: formData.active === 'true', + }; + + const response = await createOrganization(payload); + + setSuccessMessage('Organisation created successfully.'); + resetForm(); + setShowForm(false); + await fetchOrganizations(); + } catch (err) { + console.error('Add organization error:', err); + setFormError( + err?.response?.data?.message || err?.message || 'Failed to add organisation.' + ); + setSuccessMessage(''); + } finally { + setSubmitting(false); + } + }; if (loading) { return ( @@ -106,7 +146,6 @@ export default function OrgAssignmentPage() {

{error}

- + -
-

Active

-
- {selectedOrg.active ? "Yes" : "No"} -
+ {/* Success Message */} + {successMessage && ( +
+ {successMessage}
+ )} + + {/* Form */} + {showForm && ( +
+ {formError && ( +
+ {formError} +
+ )} + +
+ {/* Name */} +
+ + +
-
-

Created By

-
- {selectedOrg.createdBy || "-"} -
-
+ {/* Description */} +
+ + +
-
-

Created At

-
- {formatDate(selectedOrg.created_at)} + {/* Status Radio */} +
+ +
+ + +
+
-
-
-

Updated At

-
- {formatDate(selectedOrg.updated_at)} + {/* Form Buttons */} +
+ + +
+ + )} + + {/* Table */} + {organizations.length === 0 ? ( +
+ No organizations found.
- -
-

Staff Count

-
- {selectedOrg.staff?.length ?? 0} + ) : ( + <> +
+ + + + {['Name', 'Description', 'Active', 'Actions'].map((col) => ( + + ))} + + + + + {organizations.map((org) => ( + + + + + + + ))} + +
+ {col} +
+ {org.name || 'N/A'} + + {org.description || 'N/A'} + + + {org.active ? 'Active' : 'Inactive'} + + + +
-
-
- - - -

Overview Summary

-
-
- - Organisation data is connected to this admin account -
- -
- - {selectedOrg.staff?.length ?? 0} linked staff member(s) -
- -
- - Status: {selectedOrg.active ? "Active" : "Inactive"} -
- -
- - Ready for future organisation workflows and extensions -
-
+ {/* Pagination */} +
+
+ Total Organizations: {organizations.length} | Page 1 of 1 +
-
- -
- - +
+ + + +
+
+ + )} +
+
); } \ No newline at end of file diff --git a/guardian-admin-dashboard/src/pages/OrgDetailPage.jsx b/guardian-admin-dashboard/src/pages/OrgDetailPage.jsx new file mode 100644 index 000000000..eaa7a1f04 --- /dev/null +++ b/guardian-admin-dashboard/src/pages/OrgDetailPage.jsx @@ -0,0 +1,213 @@ +import { motion } from "framer-motion"; +import { + Building2, + CalendarDays, + FileText, + RefreshCcw, + ShieldCheck, + Users, +} from "lucide-react"; +import Button from "../components/common/Button"; + +function formatDate(dateValue) { + if (!dateValue) return "-"; + const date = new Date(dateValue); + if (Number.isNaN(date.getTime())) return "-"; + return date.toLocaleDateString("en-AU", { + day: "2-digit", + month: "short", + year: "numeric", + }); +} + +export default function OrgDetailPage({ org, onBack }) { + + const selectedOrg = org || { + _id: "1", + name: "Guardian Health Org", + description: "Primary org for admin testing", + active: true, + createdBy: "admin001", + created_at: "2026-04-11", + updated_at: "2026-04-11", + staff: [{}, {}, {}], + }; + + const stats = [ + { + title: "Staff Members", + value: selectedOrg.staff?.length ?? 0, + icon: Users, + description: "Staff currently linked with this organisation.", + }, + { + title: "Status", + value: selectedOrg.active ? "Active" : "Inactive", + icon: ShieldCheck, + description: "Current organisation status from backend data.", + }, + { + title: "Created On", + value: formatDate(selectedOrg.created_at), + icon: CalendarDays, + description: "Date this organisation record was created.", + }, + ]; + + return ( +
+ {/* Back button */} +
+ +
+ + {/* Stats Cards */} +
+ {stats.map((item, index) => { + const Icon = item.icon; + return ( + +
+
+

{item.title}

+

{item.value}

+
+
+ +
+
+

{item.description}

+
+ ); + })} +
+ + {/* Organisation Details + Overview Summary */} +
+ +
+

Organisation Details

+
+ +
+
+

Organisation ID

+
+ {selectedOrg._id || "-"} +
+
+ +
+

Name

+
{selectedOrg.name || "-"}
+
+ +
+

Description

+
+ {selectedOrg.description || "No description available."} +
+
+ +
+

Active

+
+ {selectedOrg.active ? "Yes" : "No"} +
+
+ +
+

Created By

+
+ {selectedOrg.createdBy || "-"} +
+
+ +
+

Created At

+
+ {formatDate(selectedOrg.created_at)} +
+
+ +
+

Updated At

+
+ {formatDate(selectedOrg.updated_at)} +
+
+ +
+

Staff Count

+
+ {selectedOrg.staff?.length ?? 0} +
+
+
+
+ + +

Overview Summary

+ +
+
+ + Organisation data is connected to this admin account +
+ +
+ + {selectedOrg.staff?.length ?? 0} linked staff member(s) +
+ +
+ + Status: {selectedOrg.active ? "Active" : "Inactive"} +
+ +
+ + Ready for future organisation workflows and extensions +
+
+ +
+ +
+
+
+
+ ); +} \ No newline at end of file diff --git a/guardian-admin-dashboard/src/services/orgService.js b/guardian-admin-dashboard/src/services/orgService.js index 81c5ca8ed..7a1fcec60 100644 --- a/guardian-admin-dashboard/src/services/orgService.js +++ b/guardian-admin-dashboard/src/services/orgService.js @@ -23,4 +23,18 @@ export async function getMyOrganizations() { } ] }; +} + +import api from "./api"; + +export async function getOrganizations() { + const response = await api.get('/orgs/mine'); + console.log('GET my organizations response:', response.data); + return response.data; +} + +export async function createOrganization(orgData) { + const response = await api.post('/orgs', orgData); + console.log('POST create organization response:', response.data); + return response.data; } \ No newline at end of file