@appcorp/fusion-storybook 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +147 -0
- package/base-modules/admission/cache.d.ts +14 -0
- package/base-modules/admission/cache.js +31 -0
- package/base-modules/admission/constants.d.ts +32 -0
- package/base-modules/admission/constants.js +37 -0
- package/base-modules/admission/context.d.ts +369 -0
- package/base-modules/admission/context.js +755 -0
- package/base-modules/admission/filter.d.ts +1 -0
- package/base-modules/admission/filter.js +31 -0
- package/base-modules/admission/form.d.ts +1 -0
- package/base-modules/admission/form.js +86 -0
- package/base-modules/admission/more-actions.d.ts +1 -0
- package/base-modules/admission/more-actions.js +5 -0
- package/base-modules/admission/page.d.ts +16 -0
- package/base-modules/admission/page.js +128 -0
- package/base-modules/admission/validate.d.ts +38 -0
- package/base-modules/admission/validate.js +70 -0
- package/base-modules/admission/view.d.ts +1 -0
- package/base-modules/admission/view.js +40 -0
- package/base-modules/discount-code/cache.d.ts +27 -0
- package/base-modules/discount-code/cache.js +46 -0
- package/base-modules/discount-code/constants.d.ts +19 -0
- package/base-modules/discount-code/constants.js +26 -0
- package/base-modules/discount-code/context.d.ts +154 -0
- package/base-modules/discount-code/context.js +416 -0
- package/base-modules/discount-code/filter.d.ts +9 -0
- package/base-modules/discount-code/filter.js +14 -0
- package/base-modules/discount-code/form.d.ts +1 -0
- package/base-modules/discount-code/form.js +44 -0
- package/base-modules/discount-code/more-actions.d.ts +9 -0
- package/base-modules/discount-code/more-actions.js +13 -0
- package/base-modules/discount-code/page.d.ts +16 -0
- package/base-modules/discount-code/page.js +120 -0
- package/base-modules/discount-code/validate.d.ts +19 -0
- package/base-modules/discount-code/validate.js +38 -0
- package/base-modules/discount-code/view.d.ts +1 -0
- package/base-modules/discount-code/view.js +26 -0
- package/base-modules/family/cache.d.ts +14 -0
- package/base-modules/family/cache.js +31 -0
- package/base-modules/family/constants.d.ts +22 -0
- package/base-modules/family/constants.js +26 -0
- package/base-modules/family/context.d.ts +173 -0
- package/base-modules/family/context.js +441 -0
- package/base-modules/family/filter.d.ts +1 -0
- package/base-modules/family/filter.js +28 -0
- package/base-modules/family/form.d.ts +1 -0
- package/base-modules/family/form.js +12 -0
- package/base-modules/family/more-actions.d.ts +1 -0
- package/base-modules/family/more-actions.js +5 -0
- package/base-modules/family/page.d.ts +16 -0
- package/base-modules/family/page.js +120 -0
- package/base-modules/family/validate.d.ts +15 -0
- package/base-modules/family/validate.js +18 -0
- package/base-modules/family/view.d.ts +1 -0
- package/base-modules/family/view.js +18 -0
- package/base-modules/family-member/cache.d.ts +14 -0
- package/base-modules/family-member/cache.js +31 -0
- package/base-modules/family-member/constants.d.ts +22 -0
- package/base-modules/family-member/constants.js +26 -0
- package/base-modules/family-member/context.d.ts +215 -0
- package/base-modules/family-member/context.js +486 -0
- package/base-modules/family-member/filter.d.ts +1 -0
- package/base-modules/family-member/filter.js +28 -0
- package/base-modules/family-member/form.d.ts +1 -0
- package/base-modules/family-member/form.js +17 -0
- package/base-modules/family-member/more-actions.d.ts +1 -0
- package/base-modules/family-member/more-actions.js +5 -0
- package/base-modules/family-member/page.d.ts +16 -0
- package/base-modules/family-member/page.js +122 -0
- package/base-modules/family-member/validate.d.ts +24 -0
- package/base-modules/family-member/validate.js +27 -0
- package/base-modules/family-member/view.d.ts +1 -0
- package/base-modules/family-member/view.js +40 -0
- package/base-modules/student-profile/cache.d.ts +14 -0
- package/base-modules/student-profile/cache.js +31 -0
- package/base-modules/student-profile/constants.d.ts +105 -0
- package/base-modules/student-profile/constants.js +132 -0
- package/base-modules/student-profile/context.d.ts +290 -0
- package/base-modules/student-profile/context.js +583 -0
- package/base-modules/student-profile/filter.d.ts +1 -0
- package/base-modules/student-profile/filter.js +26 -0
- package/base-modules/student-profile/form.d.ts +1 -0
- package/base-modules/student-profile/form.js +19 -0
- package/base-modules/student-profile/more-actions.d.ts +1 -0
- package/base-modules/student-profile/more-actions.js +5 -0
- package/base-modules/student-profile/page.d.ts +9 -0
- package/base-modules/student-profile/page.js +86 -0
- package/base-modules/student-profile/validate.d.ts +23 -0
- package/base-modules/student-profile/validate.js +34 -0
- package/base-modules/student-profile/view.d.ts +1 -0
- package/base-modules/student-profile/view.js +29 -0
- package/base-modules/workspace/cache.d.ts +9 -0
- package/base-modules/workspace/cache.js +28 -0
- package/base-modules/workspace/constants.d.ts +10 -0
- package/base-modules/workspace/constants.js +18 -0
- package/base-modules/workspace/context.d.ts +187 -0
- package/base-modules/workspace/context.js +293 -0
- package/base-modules/workspace/drawer.d.ts +1 -0
- package/base-modules/workspace/drawer.js +24 -0
- package/base-modules/workspace/filter.d.ts +1 -0
- package/base-modules/workspace/filter.js +13 -0
- package/base-modules/workspace/form.d.ts +1 -0
- package/base-modules/workspace/form.js +40 -0
- package/base-modules/workspace/more-actions.d.ts +1 -0
- package/base-modules/workspace/more-actions.js +13 -0
- package/base-modules/workspace/page.d.ts +1 -0
- package/base-modules/workspace/page.js +31 -0
- package/base-modules/workspace/validate.d.ts +9 -0
- package/base-modules/workspace/validate.js +8 -0
- package/base-modules/workspace/view.d.ts +1 -0
- package/base-modules/workspace/view.js +52 -0
- package/components/rbac-no-access.d.ts +6 -0
- package/components/rbac-no-access.js +4 -0
- package/constants.d.ts +81 -0
- package/constants.js +81 -0
- package/lib/utils.d.ts +2 -0
- package/lib/utils.js +5 -0
- package/package.json +104 -0
- package/tsconfig.build.tsbuildinfo +1 -0
- package/type.d.ts +1141 -0
- package/type.js +427 -0
- package/utils/admission-pdf.d.ts +78 -0
- package/utils/admission-pdf.js +73 -0
- package/utils/clear-cache.d.ts +1 -0
- package/utils/clear-cache.js +8 -0
- package/utils/format-value.d.ts +1 -0
- package/utils/format-value.js +1 -0
- package/utils/pdf-generator.d.ts +41 -0
- package/utils/pdf-generator.js +107 -0
- package/utils/resolve-rbac-permissions.d.ts +11 -0
- package/utils/resolve-rbac-permissions.js +251 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* Family Member Page Component
|
|
5
|
+
*
|
|
6
|
+
* Thin wrapper around GenericModulePage. All handlers, header actions, and row
|
|
7
|
+
* actions live in context.tsx — this file only owns:
|
|
8
|
+
* - tableBodyCols (static, module-level constant)
|
|
9
|
+
* - familyMemberConfig (memoised on locale change only; size fixed so the
|
|
10
|
+
* component type produced by createGenericModulePage never changes at
|
|
11
|
+
* runtime, preventing the infinite-remount re-render loop)
|
|
12
|
+
* - permission guard
|
|
13
|
+
*/
|
|
14
|
+
import { useMemo } from "react";
|
|
15
|
+
import { COMPONENT_TYPE } from "@appcorp/shadcn/components/enhanced-table";
|
|
16
|
+
import { createGenericModulePage, } from "@react-pakistan/util-functions/factory/generic-component-factory";
|
|
17
|
+
import { useFamilyMemberModule, FamilyMemberProvider, FAMILY_MEMBER_DRAWER, FAMILY_MEMBER_ACTION_TYPES, } from "./context";
|
|
18
|
+
import { FamilyMemberFilter } from "./filter";
|
|
19
|
+
import { FamilyMemberForm } from "./form";
|
|
20
|
+
import { FamilyMemberMoreActions } from "./more-actions";
|
|
21
|
+
import { FamilyMemberView } from "./view";
|
|
22
|
+
import { resolveRbacPermissions } from "@/utils/resolve-rbac-permissions";
|
|
23
|
+
import { RbacNoAccess } from "@/components/rbac-no-access";
|
|
24
|
+
import { useTranslations } from "next-intl";
|
|
25
|
+
// ============================================================================
|
|
26
|
+
// TABLE COLUMN CONFIGURATION (static — no runtime deps)
|
|
27
|
+
// ============================================================================
|
|
28
|
+
const tableBodyCols = [
|
|
29
|
+
{ componentType: COMPONENT_TYPE.ID, key: "id" },
|
|
30
|
+
{ componentType: COMPONENT_TYPE.BOLD_TEXT, key: ["firstName", "lastName"] },
|
|
31
|
+
{ componentType: COMPONENT_TYPE.TEXT, key: "role" },
|
|
32
|
+
{ componentType: COMPONENT_TYPE.TEXT, key: "email" },
|
|
33
|
+
{ componentType: COMPONENT_TYPE.TEXT, key: "phone" },
|
|
34
|
+
{ componentType: COMPONENT_TYPE.BOOLEAN, key: "isPrimary" },
|
|
35
|
+
{ componentType: COMPONENT_TYPE.BOOLEAN, key: "enabled" },
|
|
36
|
+
{ componentType: COMPONENT_TYPE.ACTIONS },
|
|
37
|
+
];
|
|
38
|
+
const tableColumns = [
|
|
39
|
+
{ label: "id", width: "5%" },
|
|
40
|
+
{ label: "firstName", width: "20%" },
|
|
41
|
+
{ label: "role", width: "15%" },
|
|
42
|
+
{ label: "email", width: "20%" },
|
|
43
|
+
{ label: "phone", width: "15%" },
|
|
44
|
+
{ label: "primaryContact", width: "10%" },
|
|
45
|
+
{ label: "status", width: "10%" },
|
|
46
|
+
{ label: "actions", width: "5%" },
|
|
47
|
+
];
|
|
48
|
+
// ============================================================================
|
|
49
|
+
// TRANSLATED COLUMNS HELPER
|
|
50
|
+
// ============================================================================
|
|
51
|
+
const getTranslatedColumns = (t) => tableColumns.map((col) => (Object.assign(Object.assign({}, col), { label: t(col.label) })));
|
|
52
|
+
// ============================================================================
|
|
53
|
+
// COMPONENT FACTORY (creates JSX elements when config is created, not during render)
|
|
54
|
+
// ============================================================================
|
|
55
|
+
const createComponentInstances = () => ({
|
|
56
|
+
filter: _jsx(FamilyMemberFilter, {}),
|
|
57
|
+
form: _jsx(FamilyMemberForm, {}),
|
|
58
|
+
moreActions: _jsx(FamilyMemberMoreActions, {}),
|
|
59
|
+
view: _jsx(FamilyMemberView, {}),
|
|
60
|
+
});
|
|
61
|
+
// ============================================================================
|
|
62
|
+
// CONFIG CREATION HELPER
|
|
63
|
+
// ============================================================================
|
|
64
|
+
const createFamilyMemberConfig = (t, drawer, dispatch) => {
|
|
65
|
+
const components = createComponentInstances();
|
|
66
|
+
return {
|
|
67
|
+
moduleName: "familyMember",
|
|
68
|
+
tableColumns: getTranslatedColumns(t),
|
|
69
|
+
cancelLabel: t("cancel"),
|
|
70
|
+
drawerTitle: t("familyMember"),
|
|
71
|
+
filterContent: components.filter,
|
|
72
|
+
formContent: components.form,
|
|
73
|
+
moreActionsContent: components.moreActions,
|
|
74
|
+
saveLabel: t("save"),
|
|
75
|
+
searchPlaceholder: t("searchFamilyMembers"),
|
|
76
|
+
tableDescription: t("manageFamilyMembersAndTheirInformation"),
|
|
77
|
+
tableTitle: t("familyMember"),
|
|
78
|
+
viewContent: components.view,
|
|
79
|
+
size: drawer === FAMILY_MEMBER_DRAWER.FORM_DRAWER ? "full" : "small",
|
|
80
|
+
onClearFilters: () => {
|
|
81
|
+
dispatch({ type: FAMILY_MEMBER_ACTION_TYPES.RESET_FORM });
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
// ============================================================================
|
|
86
|
+
// STABLE PAGE COMPONENT (created once, outside render)
|
|
87
|
+
// ============================================================================
|
|
88
|
+
const GenericFamilyMemberPage = createGenericModulePage({
|
|
89
|
+
moduleName: "familyMember",
|
|
90
|
+
tableColumns: [],
|
|
91
|
+
cancelLabel: "",
|
|
92
|
+
drawerTitle: "",
|
|
93
|
+
filterContent: _jsx(FamilyMemberFilter, {}),
|
|
94
|
+
formContent: _jsx(FamilyMemberForm, {}),
|
|
95
|
+
moreActionsContent: _jsx(FamilyMemberMoreActions, {}),
|
|
96
|
+
saveLabel: "",
|
|
97
|
+
searchPlaceholder: "",
|
|
98
|
+
tableDescription: "",
|
|
99
|
+
tableTitle: "",
|
|
100
|
+
viewContent: _jsx(FamilyMemberView, {}),
|
|
101
|
+
size: "small",
|
|
102
|
+
onClearFilters: () => { },
|
|
103
|
+
});
|
|
104
|
+
// ============================================================================
|
|
105
|
+
// INNER PAGE (requires FamilyMemberProvider context)
|
|
106
|
+
// ============================================================================
|
|
107
|
+
const FamilyMemberPageInner = ({ userRole }) => {
|
|
108
|
+
const t = useTranslations("familyMember");
|
|
109
|
+
const context = useFamilyMemberModule();
|
|
110
|
+
// Memoize permission check to avoid recalculation on every render
|
|
111
|
+
const hasPermission = useMemo(() => resolveRbacPermissions({
|
|
112
|
+
userRole,
|
|
113
|
+
moduleName: "People Management",
|
|
114
|
+
}), [userRole]);
|
|
115
|
+
// Memoize config creation
|
|
116
|
+
const familyMemberConfig = useMemo(() => createFamilyMemberConfig(t, context.state.drawer, context.dispatch), [t, context.state.drawer, context.dispatch]);
|
|
117
|
+
if (!hasPermission) {
|
|
118
|
+
return _jsx(RbacNoAccess, { moduleName: "People Management" });
|
|
119
|
+
}
|
|
120
|
+
return (_jsx("div", { className: "p-4", children: _jsx(GenericFamilyMemberPage, { config: familyMemberConfig, context: context, tableBodyCols: tableBodyCols }) }));
|
|
121
|
+
};
|
|
122
|
+
export const FamilyMemberPage = ({ userRole }) => (_jsx(FamilyMemberProvider, { children: _jsx(FamilyMemberPageInner, { userRole: userRole }) }));
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FamilyMember Validation Schema
|
|
3
|
+
*
|
|
4
|
+
* Zod validation schemas for family-member form data.
|
|
5
|
+
*/
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
export declare const familyMemberFormValidation: z.ZodObject<{
|
|
8
|
+
familyId: z.ZodString;
|
|
9
|
+
firstName: z.ZodString;
|
|
10
|
+
lastName: z.ZodString;
|
|
11
|
+
role: z.ZodString;
|
|
12
|
+
dateOfBirth: z.ZodOptional<z.ZodString>;
|
|
13
|
+
gender: z.ZodOptional<z.ZodString>;
|
|
14
|
+
bloodGroup: z.ZodOptional<z.ZodString>;
|
|
15
|
+
phone: z.ZodOptional<z.ZodString>;
|
|
16
|
+
email: z.ZodUnion<[z.ZodOptional<z.ZodString>, z.ZodLiteral<"">]>;
|
|
17
|
+
relationship: z.ZodOptional<z.ZodString>;
|
|
18
|
+
occupation: z.ZodOptional<z.ZodString>;
|
|
19
|
+
emergencyPhone: z.ZodOptional<z.ZodString>;
|
|
20
|
+
idNumber: z.ZodOptional<z.ZodString>;
|
|
21
|
+
avatar: z.ZodOptional<z.ZodString>;
|
|
22
|
+
isPrimary: z.ZodOptional<z.ZodBoolean>;
|
|
23
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
24
|
+
}, z.core.$strip>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* FamilyMember Validation Schema
|
|
3
|
+
*
|
|
4
|
+
* Zod validation schemas for family-member form data.
|
|
5
|
+
*/
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// VALIDATION SCHEMA
|
|
9
|
+
// ============================================================================
|
|
10
|
+
export const familyMemberFormValidation = z.object({
|
|
11
|
+
familyId: z.string().min(1, "Family is required"),
|
|
12
|
+
firstName: z.string().min(1, "First name is required"),
|
|
13
|
+
lastName: z.string().min(1, "Last name is required"),
|
|
14
|
+
role: z.string().min(1, "Role is required"),
|
|
15
|
+
dateOfBirth: z.string().optional(),
|
|
16
|
+
gender: z.string().optional(),
|
|
17
|
+
bloodGroup: z.string().optional(),
|
|
18
|
+
phone: z.string().optional(),
|
|
19
|
+
email: z.string().email().optional().or(z.literal("")),
|
|
20
|
+
relationship: z.string().optional(),
|
|
21
|
+
occupation: z.string().optional(),
|
|
22
|
+
emergencyPhone: z.string().optional(),
|
|
23
|
+
idNumber: z.string().optional(),
|
|
24
|
+
avatar: z.string().optional(),
|
|
25
|
+
isPrimary: z.boolean().optional(),
|
|
26
|
+
enabled: z.boolean().optional(),
|
|
27
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const FamilyMemberView: () => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* FamilyMember View Component
|
|
5
|
+
*
|
|
6
|
+
* Read-only detail view for a family member record.
|
|
7
|
+
*/
|
|
8
|
+
import { Avatar, AvatarFallback, AvatarImage, } from "@appcorp/shadcn/components/ui/avatar";
|
|
9
|
+
import { Badge } from "@appcorp/shadcn/components/ui/badge";
|
|
10
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@appcorp/shadcn/components/ui/card";
|
|
11
|
+
import { Separator } from "@appcorp/shadcn/components/ui/separator";
|
|
12
|
+
import { DATE_FORMATS, formatDate } from "@react-pakistan/util-functions";
|
|
13
|
+
import { Briefcase, Calendar, CheckCircle2, Heart, Mail, Phone, ShieldCheck, User, Users, XCircle, } from "lucide-react";
|
|
14
|
+
import { useFamilyMemberModule } from "./context";
|
|
15
|
+
import { useTranslations } from "next-intl";
|
|
16
|
+
import { formatValue } from "@/utils/format-value";
|
|
17
|
+
export const FamilyMemberView = () => {
|
|
18
|
+
const { state } = useFamilyMemberModule();
|
|
19
|
+
const { avatar, bloodGroup, dateOfBirth, email, emergencyPhone, enabled, firstName, gender, idNumber, isPrimary, lastName, occupation, phone, relationship, role, } = state;
|
|
20
|
+
const t = useTranslations("familyMember");
|
|
21
|
+
const fullName = [firstName, lastName].filter(Boolean).join(" ") || t("familyMember");
|
|
22
|
+
const initials = `${(firstName === null || firstName === void 0 ? void 0 : firstName[0]) || ""}${(lastName === null || lastName === void 0 ? void 0 : lastName[0]) || ""}`
|
|
23
|
+
.toUpperCase()
|
|
24
|
+
.slice(0, 2);
|
|
25
|
+
const formatEnumValue = (value) => {
|
|
26
|
+
if (!value)
|
|
27
|
+
return "—";
|
|
28
|
+
return value.toLowerCase().replace(/_/g, " ");
|
|
29
|
+
};
|
|
30
|
+
const formatDateValue = (value) => {
|
|
31
|
+
if (!value)
|
|
32
|
+
return "—";
|
|
33
|
+
return formatDate(new Date(value).toISOString(), DATE_FORMATS.LOCALE_DATE);
|
|
34
|
+
};
|
|
35
|
+
return (_jsxs("div", { className: "space-y-4", children: [_jsx(Card, { children: _jsx(CardContent, { className: "pt-6", children: _jsxs("div", { className: "flex items-center gap-6", children: [_jsxs(Avatar, { className: "h-24 w-24", children: [_jsx(AvatarImage, { src: avatar || undefined, alt: fullName }), _jsx(AvatarFallback, { className: "text-2xl", children: initials || "FM" })] }), _jsxs("div", { className: "flex-1", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("h2", { className: "text-2xl font-bold", children: fullName }), enabled ? (_jsxs(Badge, { variant: "default", className: "gap-1", children: [_jsx(CheckCircle2, { className: "h-3 w-3" }), t("active")] })) : (_jsxs(Badge, { variant: "secondary", className: "gap-1", children: [_jsx(XCircle, { className: "h-3 w-3" }), t("inactive")] })), isPrimary && (_jsxs(Badge, { variant: "outline", className: "gap-1", children: [_jsx(ShieldCheck, { className: "h-3 w-3" }), t("primaryContact")] }))] }), _jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: t("familyMemberProfile") }), _jsxs("div", { className: "mt-3 flex flex-wrap items-center gap-2", children: [role ? (_jsx(Badge, { variant: "secondary", className: "capitalize", children: formatEnumValue(role) })) : null, relationship ? (_jsx(Badge, { variant: "outline", className: "capitalize", children: formatEnumValue(relationship) })) : null, gender ? (_jsx(Badge, { variant: "outline", className: "capitalize", children: formatEnumValue(gender) })) : null] })] })] }) }) }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(User, { className: "h-5 w-5 text-primary" }), _jsx(CardTitle, { className: "text-lg", children: t("personalInformation") })] }), _jsx(CardDescription, { children: t("basicIdentityAndProfileDetails") })] }), _jsx(Separator, {}), _jsx(CardContent, { className: "pt-6", children: _jsxs("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-2", children: [_jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-sm font-medium text-muted-foreground", children: t("firstName") }), _jsx("p", { className: "text-base", children: formatValue(firstName) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-sm font-medium text-muted-foreground", children: t("lastName") }), _jsx("p", { className: "text-base", children: formatValue(lastName) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-sm font-medium text-muted-foreground", children: t("role") }), role ? (_jsx(Badge, { variant: "secondary", className: "capitalize", children: formatEnumValue(role) })) : (_jsx("p", { className: "text-base", children: "\u2014" }))] }), _jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Calendar, { className: "h-4 w-4 text-muted-foreground" }), _jsx("p", { className: "text-sm font-medium text-muted-foreground", children: t("dateOfBirth") })] }), _jsx("p", { className: "text-base", children: formatDateValue(dateOfBirth) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-sm font-medium text-muted-foreground", children: t("gender") }), gender ? (_jsx(Badge, { variant: "outline", className: "capitalize", children: formatEnumValue(gender) })) : (_jsx("p", { className: "text-base", children: "\u2014" }))] }), _jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Heart, { className: "h-4 w-4 text-muted-foreground" }), _jsx("p", { className: "text-sm font-medium text-muted-foreground", children: t("bloodGroup") })] }), _jsx("p", { className: "text-base", children: formatValue(bloodGroup) })] }), _jsxs("div", { className: "space-y-1 md:col-span-2", children: [_jsx("p", { className: "text-sm font-medium text-muted-foreground", children: t("idNumber") }), _jsx("p", { className: "text-base", children: formatValue(idNumber) })] })] }) })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Phone, { className: "h-5 w-5 text-primary" }), _jsx(CardTitle, { className: "text-lg", children: t("contactInformation") })] }), _jsx(CardDescription, { children: t("reachabilityAndEmergencyContactDetails") })] }), _jsx(Separator, {}), _jsx(CardContent, { className: "pt-6", children: _jsxs("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-2", children: [_jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Phone, { className: "h-4 w-4 text-muted-foreground" }), _jsx("p", { className: "text-sm font-medium text-muted-foreground", children: t("phone") })] }), _jsx("p", { className: "text-base", children: formatValue(phone) })] }), _jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Mail, { className: "h-4 w-4 text-muted-foreground" }), _jsx("p", { className: "text-sm font-medium text-muted-foreground", children: t("email") })] }), _jsx("p", { className: "text-base", children: formatValue(email) })] }), _jsxs("div", { className: "space-y-1 md:col-span-2", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Phone, { className: "h-4 w-4 text-muted-foreground" }), _jsx("p", { className: "text-sm font-medium text-muted-foreground", children: t("emergencyPhone") })] }), _jsx("p", { className: "text-base", children: formatValue(emergencyPhone) })] })] }) })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Users, { className: "h-5 w-5 text-primary" }), _jsx(CardTitle, { className: "text-lg", children: t("familyRole") })] }), _jsx(CardDescription, { children: t("relationshipAndHouseholdResponsibilities") })] }), _jsx(Separator, {}), _jsx(CardContent, { className: "pt-6", children: _jsxs("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-2", children: [_jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-sm font-medium text-muted-foreground", children: t("relationship") }), relationship ? (_jsx(Badge, { variant: "secondary", className: "capitalize", children: formatEnumValue(relationship) })) : (_jsx("p", { className: "text-base", children: "\u2014" }))] }), _jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Briefcase, { className: "h-4 w-4 text-muted-foreground" }), _jsx("p", { className: "text-sm font-medium text-muted-foreground", children: t("occupation") })] }), _jsx("p", { className: "text-base", children: formatValue(occupation) })] })] }) })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(ShieldCheck, { className: "h-5 w-5 text-primary" }), _jsx(CardTitle, { className: "text-lg", children: t("status") })] }), _jsx(CardDescription, { children: t("primaryContactAndAccountActivity") })] }), _jsx(Separator, {}), _jsx(CardContent, { className: "pt-6", children: _jsxs("div", { className: "grid grid-cols-1 gap-6 md:grid-cols-2", children: [_jsxs("div", { className: "flex items-start gap-3", children: [_jsx(ShieldCheck, { className: "mt-0.5 h-5 w-5 text-primary" }), _jsxs("div", { children: [_jsx("p", { className: "font-medium", children: isPrimary ? t("primaryContact") : t("secondaryContact") }), _jsx("p", { className: "text-sm text-muted-foreground", children: isPrimary
|
|
36
|
+
? t("thisIsPrimaryFamilyContact")
|
|
37
|
+
: t("thisIsAdditionalFamilyContact") })] })] }), _jsxs("div", { className: "flex items-start gap-3", children: [enabled ? (_jsx(CheckCircle2, { className: "mt-0.5 h-5 w-5 text-green-500" })) : (_jsx(XCircle, { className: "mt-0.5 h-5 w-5 text-red-500" })), _jsxs("div", { children: [_jsx("p", { className: "font-medium", children: enabled ? t("active") : t("inactive") }), _jsx("p", { className: "text-sm text-muted-foreground", children: enabled
|
|
38
|
+
? t("thisAccountIsCurrentlyActive")
|
|
39
|
+
: t("thisAccountIsCurrentlyInactive") })] })] })] }) })] })] }));
|
|
40
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Student Profile Module Cache Utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides localStorage-based caching for student profiles using generic cache system.
|
|
5
|
+
*/
|
|
6
|
+
import { StudentProfileBE } from "@/type";
|
|
7
|
+
export declare const getCachedStudentProfilesSync: () => import("@react-pakistan/util-functions").ListResponse<StudentProfileBE>;
|
|
8
|
+
export declare const getCachedStudentProfiles: ({ params, }: {
|
|
9
|
+
params?: Record<string, unknown>;
|
|
10
|
+
}) => Promise<import("@react-pakistan/util-functions").ListResponse<StudentProfileBE>>;
|
|
11
|
+
export declare const getCachedStudentProfileById: (studentProfileId: string) => StudentProfileBE | null;
|
|
12
|
+
export declare const invalidateStudentProfilesCache: () => void;
|
|
13
|
+
export declare const preloadStudentProfiles: () => Promise<import("@react-pakistan/util-functions").ListResponse<StudentProfileBE>>;
|
|
14
|
+
export declare const isStudentProfilesCacheStale: () => boolean;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Student Profile Module Cache Utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides localStorage-based caching for student profiles using generic cache system.
|
|
5
|
+
*/
|
|
6
|
+
import { LS_KEYS } from "@/constants";
|
|
7
|
+
import { STUDENT_PROFILE_API_ROUTES } from "./constants";
|
|
8
|
+
import { getCachedData, getCachedDataSync, getCachedItemById, invalidateCache, isCacheStale, preloadCache, } from "@react-pakistan/util-functions";
|
|
9
|
+
// ============================================================================
|
|
10
|
+
// CACHE CONFIGURATION
|
|
11
|
+
// ============================================================================
|
|
12
|
+
const STUDENT_PROFILE_CACHE_CONFIG = {
|
|
13
|
+
apiUrl: STUDENT_PROFILE_API_ROUTES.UNIT,
|
|
14
|
+
cacheKey: LS_KEYS.STUDENT_PROFILES,
|
|
15
|
+
};
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// STUDENT_PROFILE-SPECIFIC CACHE FUNCTIONS
|
|
18
|
+
// ============================================================================
|
|
19
|
+
export const getCachedStudentProfilesSync = () => getCachedDataSync(LS_KEYS.STUDENT_PROFILES);
|
|
20
|
+
export const getCachedStudentProfiles = ({ params, }) => getCachedData({
|
|
21
|
+
config: STUDENT_PROFILE_CACHE_CONFIG,
|
|
22
|
+
params,
|
|
23
|
+
headers: {
|
|
24
|
+
"Content-Type": "application/json",
|
|
25
|
+
"x-api-token": process.env.NEXT_PUBLIC_API_KEY,
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
export const getCachedStudentProfileById = (studentProfileId) => getCachedItemById(LS_KEYS.STUDENT_PROFILES, studentProfileId);
|
|
29
|
+
export const invalidateStudentProfilesCache = () => invalidateCache(LS_KEYS.STUDENT_PROFILES);
|
|
30
|
+
export const preloadStudentProfiles = () => preloadCache(STUDENT_PROFILE_CACHE_CONFIG);
|
|
31
|
+
export const isStudentProfilesCacheStale = () => isCacheStale(LS_KEYS.STUDENT_PROFILES);
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Student Constants
|
|
3
|
+
*
|
|
4
|
+
* Organization:
|
|
5
|
+
* - Page Configuration
|
|
6
|
+
* - API Routes
|
|
7
|
+
* - Table Configuration
|
|
8
|
+
* - Status Options
|
|
9
|
+
* - Gender Options
|
|
10
|
+
*/
|
|
11
|
+
import { COMPONENT_TYPE } from "@appcorp/shadcn/components/enhanced-table";
|
|
12
|
+
export declare const pageLimit: number;
|
|
13
|
+
export declare const STUDENT_PROFILE_API_ROUTES: Record<string, string>;
|
|
14
|
+
export declare const tableHeadItems: {
|
|
15
|
+
label: string;
|
|
16
|
+
width: string;
|
|
17
|
+
}[];
|
|
18
|
+
export declare const tableBodyCols: ({
|
|
19
|
+
componentType: COMPONENT_TYPE;
|
|
20
|
+
key: string;
|
|
21
|
+
textFormatter?: undefined;
|
|
22
|
+
} | {
|
|
23
|
+
componentType: COMPONENT_TYPE;
|
|
24
|
+
key: string[];
|
|
25
|
+
textFormatter?: undefined;
|
|
26
|
+
} | {
|
|
27
|
+
componentType: COMPONENT_TYPE;
|
|
28
|
+
key: string;
|
|
29
|
+
textFormatter: (value: unknown) => string;
|
|
30
|
+
} | {
|
|
31
|
+
componentType: COMPONENT_TYPE;
|
|
32
|
+
key?: undefined;
|
|
33
|
+
textFormatter?: undefined;
|
|
34
|
+
})[];
|
|
35
|
+
export declare const STATUS_OPTIONS: readonly [{
|
|
36
|
+
readonly label: "All Status";
|
|
37
|
+
readonly value: "";
|
|
38
|
+
}, {
|
|
39
|
+
readonly label: "Active";
|
|
40
|
+
readonly value: "ACTIVE";
|
|
41
|
+
}, {
|
|
42
|
+
readonly label: "Inactive";
|
|
43
|
+
readonly value: "INACTIVE";
|
|
44
|
+
}, {
|
|
45
|
+
readonly label: "Graduated";
|
|
46
|
+
readonly value: "GRADUATED";
|
|
47
|
+
}, {
|
|
48
|
+
readonly label: "Transferred";
|
|
49
|
+
readonly value: "TRANSFERRED";
|
|
50
|
+
}, {
|
|
51
|
+
readonly label: "Expelled";
|
|
52
|
+
readonly value: "EXPELLED";
|
|
53
|
+
}];
|
|
54
|
+
export declare const STATUS_BADGE_COLORS: Record<string, string>;
|
|
55
|
+
export declare const GENDER_OPTIONS: readonly [{
|
|
56
|
+
readonly label: "All Genders";
|
|
57
|
+
readonly value: "";
|
|
58
|
+
}, {
|
|
59
|
+
readonly label: "Male";
|
|
60
|
+
readonly value: "MALE";
|
|
61
|
+
}, {
|
|
62
|
+
readonly label: "Female";
|
|
63
|
+
readonly value: "FEMALE";
|
|
64
|
+
}, {
|
|
65
|
+
readonly label: "Other";
|
|
66
|
+
readonly value: "OTHER";
|
|
67
|
+
}];
|
|
68
|
+
export declare const ENABLED_OPTIONS: readonly [{
|
|
69
|
+
readonly label: "All";
|
|
70
|
+
readonly value: "";
|
|
71
|
+
}, {
|
|
72
|
+
readonly label: "Enabled";
|
|
73
|
+
readonly value: "true";
|
|
74
|
+
}, {
|
|
75
|
+
readonly label: "Disabled";
|
|
76
|
+
readonly value: "false";
|
|
77
|
+
}];
|
|
78
|
+
export declare const BLOOD_GROUP_OPTIONS: readonly [{
|
|
79
|
+
readonly label: "Select Blood Group";
|
|
80
|
+
readonly value: "";
|
|
81
|
+
}, {
|
|
82
|
+
readonly label: "A+";
|
|
83
|
+
readonly value: "A+";
|
|
84
|
+
}, {
|
|
85
|
+
readonly label: "A-";
|
|
86
|
+
readonly value: "A-";
|
|
87
|
+
}, {
|
|
88
|
+
readonly label: "B+";
|
|
89
|
+
readonly value: "B+";
|
|
90
|
+
}, {
|
|
91
|
+
readonly label: "B-";
|
|
92
|
+
readonly value: "B-";
|
|
93
|
+
}, {
|
|
94
|
+
readonly label: "AB+";
|
|
95
|
+
readonly value: "AB+";
|
|
96
|
+
}, {
|
|
97
|
+
readonly label: "AB-";
|
|
98
|
+
readonly value: "AB-";
|
|
99
|
+
}, {
|
|
100
|
+
readonly label: "O+";
|
|
101
|
+
readonly value: "O+";
|
|
102
|
+
}, {
|
|
103
|
+
readonly label: "O-";
|
|
104
|
+
readonly value: "O-";
|
|
105
|
+
}];
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Student Constants
|
|
3
|
+
*
|
|
4
|
+
* Organization:
|
|
5
|
+
* - Page Configuration
|
|
6
|
+
* - API Routes
|
|
7
|
+
* - Table Configuration
|
|
8
|
+
* - Status Options
|
|
9
|
+
* - Gender Options
|
|
10
|
+
*/
|
|
11
|
+
import { COMPONENT_TYPE } from "@appcorp/shadcn/components/enhanced-table";
|
|
12
|
+
// ============================================================================
|
|
13
|
+
// PAGE CONFIGURATION
|
|
14
|
+
// ============================================================================
|
|
15
|
+
export const pageLimit = Number(process.env.NEXT_PUBLIC_PAGE_LIMIT) || 10;
|
|
16
|
+
// ============================================================================
|
|
17
|
+
// API ROUTES
|
|
18
|
+
// ============================================================================
|
|
19
|
+
export const STUDENT_PROFILE_API_ROUTES = {
|
|
20
|
+
UNIT: "/api/v1/student-profile",
|
|
21
|
+
};
|
|
22
|
+
// ============================================================================
|
|
23
|
+
// TABLE CONFIGURATION
|
|
24
|
+
// ============================================================================
|
|
25
|
+
export const tableHeadItems = [
|
|
26
|
+
{ label: "ID", width: "5%" },
|
|
27
|
+
{ label: "First Name", width: "15%" },
|
|
28
|
+
{ label: "Last Name", width: "15%" },
|
|
29
|
+
{ label: "Computer Number", width: "15%" },
|
|
30
|
+
{ label: "Discount Code", width: "15%" },
|
|
31
|
+
{ label: "Enrolled Class", width: "15%" },
|
|
32
|
+
{ label: "Status", width: "10%" },
|
|
33
|
+
{ label: "Enabled", width: "5%" },
|
|
34
|
+
{ label: "Actions", width: "5%" },
|
|
35
|
+
];
|
|
36
|
+
export const tableBodyCols = [
|
|
37
|
+
{
|
|
38
|
+
componentType: COMPONENT_TYPE.ID,
|
|
39
|
+
key: "id",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
componentType: COMPONENT_TYPE.OBJECT,
|
|
43
|
+
key: ["familyMember:firstName"],
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
componentType: COMPONENT_TYPE.OBJECT,
|
|
47
|
+
key: ["familyMember:lastName"],
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
componentType: COMPONENT_TYPE.TEXT,
|
|
51
|
+
key: "computerNumber",
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
componentType: COMPONENT_TYPE.TEXT,
|
|
55
|
+
key: "discountCode",
|
|
56
|
+
textFormatter: (value) => value || "N/A",
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
componentType: COMPONENT_TYPE.TEXT,
|
|
60
|
+
key: "enrollments",
|
|
61
|
+
textFormatter: (value) => {
|
|
62
|
+
var _a;
|
|
63
|
+
const enrollments = value;
|
|
64
|
+
if (!enrollments || enrollments.length === 0)
|
|
65
|
+
return "No enrollments";
|
|
66
|
+
if (enrollments.length === 1) {
|
|
67
|
+
return ((_a = enrollments[0].course) === null || _a === void 0 ? void 0 : _a.code) || "Unknown course";
|
|
68
|
+
}
|
|
69
|
+
return `${enrollments.length} courses`;
|
|
70
|
+
},
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
componentType: COMPONENT_TYPE.TEXT,
|
|
74
|
+
key: "status",
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
componentType: COMPONENT_TYPE.BOOLEAN,
|
|
78
|
+
key: "enabled",
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
componentType: COMPONENT_TYPE.ACTIONS,
|
|
82
|
+
},
|
|
83
|
+
];
|
|
84
|
+
// ============================================================================
|
|
85
|
+
// STATUS OPTIONS
|
|
86
|
+
// ============================================================================
|
|
87
|
+
export const STATUS_OPTIONS = [
|
|
88
|
+
{ label: "All Status", value: "" },
|
|
89
|
+
{ label: "Active", value: "ACTIVE" },
|
|
90
|
+
{ label: "Inactive", value: "INACTIVE" },
|
|
91
|
+
{ label: "Graduated", value: "GRADUATED" },
|
|
92
|
+
{ label: "Transferred", value: "TRANSFERRED" },
|
|
93
|
+
{ label: "Expelled", value: "EXPELLED" },
|
|
94
|
+
];
|
|
95
|
+
export const STATUS_BADGE_COLORS = {
|
|
96
|
+
ACTIVE: "bg-green-500/10 text-green-700 dark:text-green-400",
|
|
97
|
+
INACTIVE: "bg-gray-500/10 text-gray-700 dark:text-gray-400",
|
|
98
|
+
GRADUATED: "bg-blue-500/10 text-blue-700 dark:text-blue-400",
|
|
99
|
+
TRANSFERRED: "bg-yellow-500/10 text-yellow-700 dark:text-yellow-400",
|
|
100
|
+
EXPELLED: "bg-red-500/10 text-red-700 dark:text-red-400",
|
|
101
|
+
};
|
|
102
|
+
// ============================================================================
|
|
103
|
+
// GENDER OPTIONS
|
|
104
|
+
// ============================================================================
|
|
105
|
+
export const GENDER_OPTIONS = [
|
|
106
|
+
{ label: "All Genders", value: "" },
|
|
107
|
+
{ label: "Male", value: "MALE" },
|
|
108
|
+
{ label: "Female", value: "FEMALE" },
|
|
109
|
+
{ label: "Other", value: "OTHER" },
|
|
110
|
+
];
|
|
111
|
+
// ============================================================================
|
|
112
|
+
// ENABLED OPTIONS
|
|
113
|
+
// ============================================================================
|
|
114
|
+
export const ENABLED_OPTIONS = [
|
|
115
|
+
{ label: "All", value: "" },
|
|
116
|
+
{ label: "Enabled", value: "true" },
|
|
117
|
+
{ label: "Disabled", value: "false" },
|
|
118
|
+
];
|
|
119
|
+
// ============================================================================
|
|
120
|
+
// BLOOD GROUP OPTIONS
|
|
121
|
+
// ============================================================================
|
|
122
|
+
export const BLOOD_GROUP_OPTIONS = [
|
|
123
|
+
{ label: "Select Blood Group", value: "" },
|
|
124
|
+
{ label: "A+", value: "A+" },
|
|
125
|
+
{ label: "A-", value: "A-" },
|
|
126
|
+
{ label: "B+", value: "B+" },
|
|
127
|
+
{ label: "B-", value: "B-" },
|
|
128
|
+
{ label: "AB+", value: "AB+" },
|
|
129
|
+
{ label: "AB-", value: "AB-" },
|
|
130
|
+
{ label: "O+", value: "O+" },
|
|
131
|
+
{ label: "O-", value: "O-" },
|
|
132
|
+
];
|