@appcorp/fusion-storybook 0.2.86 → 0.2.89

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.
Files changed (147) hide show
  1. package/base-modules/admission/filter.js +3 -3
  2. package/base-modules/admission/form.js +1 -1
  3. package/base-modules/admission/more-actions.js +288 -2
  4. package/base-modules/admission/view.js +1 -1
  5. package/base-modules/attendance/form.js +3 -3
  6. package/base-modules/campus/form.js +2 -1
  7. package/base-modules/campus/validate.d.ts +13 -5
  8. package/base-modules/campus/validate.js +24 -19
  9. package/base-modules/class/form.js +2 -1
  10. package/base-modules/class/more-actions.js +2 -2
  11. package/base-modules/class/validate.d.ts +10 -5
  12. package/base-modules/class/validate.js +18 -16
  13. package/base-modules/class/view.js +2 -2
  14. package/base-modules/course/form.js +2 -1
  15. package/base-modules/course/validate.d.ts +7 -5
  16. package/base-modules/course/validate.js +12 -13
  17. package/base-modules/course/view.js +3 -3
  18. package/base-modules/discount-code/constants.d.ts +1 -1
  19. package/base-modules/discount-code/constants.js +1 -1
  20. package/base-modules/discount-code/form.js +2 -1
  21. package/base-modules/discount-code/more-actions.js +1 -1
  22. package/base-modules/discount-code/page.d.ts +10 -10
  23. package/base-modules/discount-code/page.js +31 -31
  24. package/base-modules/discount-code/validate.d.ts +5 -0
  25. package/base-modules/discount-code/validate.js +8 -3
  26. package/base-modules/discount-code/view.js +2 -2
  27. package/base-modules/enrollment/form.js +3 -2
  28. package/base-modules/enrollment/more-actions.js +5 -5
  29. package/base-modules/enrollment/page.d.ts +10 -10
  30. package/base-modules/enrollment/page.js +31 -31
  31. package/base-modules/enrollment/validate.d.ts +6 -0
  32. package/base-modules/enrollment/validate.js +13 -5
  33. package/base-modules/enrollment/view.js +2 -2
  34. package/base-modules/expense/filter.js +1 -1
  35. package/base-modules/expense/form.js +3 -3
  36. package/base-modules/expense/more-actions.js +6 -6
  37. package/base-modules/expense/page.d.ts +11 -11
  38. package/base-modules/expense/page.js +34 -34
  39. package/base-modules/expense/validate.d.ts +8 -0
  40. package/base-modules/expense/validate.js +13 -5
  41. package/base-modules/expense/view.js +2 -2
  42. package/base-modules/family/context.js +1 -1
  43. package/base-modules/family/form.js +1 -1
  44. package/base-modules/family/more-actions.js +2 -2
  45. package/base-modules/family/page.d.ts +10 -10
  46. package/base-modules/family/page.js +31 -31
  47. package/base-modules/family/validate.d.ts +4 -0
  48. package/base-modules/family/validate.js +8 -1
  49. package/base-modules/family/view.js +1 -1
  50. package/base-modules/family-member/context.js +1 -1
  51. package/base-modules/family-member/form.js +2 -1
  52. package/base-modules/family-member/more-actions.js +5 -5
  53. package/base-modules/family-member/page.d.ts +40 -13
  54. package/base-modules/family-member/page.js +34 -34
  55. package/base-modules/family-member/validate.d.ts +8 -0
  56. package/base-modules/family-member/validate.js +20 -5
  57. package/base-modules/family-member/view.js +3 -3
  58. package/base-modules/fee-structure/form.js +5 -4
  59. package/base-modules/fee-structure/more-actions.js +2 -2
  60. package/base-modules/fee-structure/page.d.ts +11 -11
  61. package/base-modules/fee-structure/page.js +34 -34
  62. package/base-modules/fee-structure/validate.d.ts +6 -0
  63. package/base-modules/fee-structure/validate.js +12 -3
  64. package/base-modules/fee-structure/view.js +3 -3
  65. package/base-modules/rbac/assign-permissions.js +9 -5
  66. package/base-modules/rbac/filter.js +5 -3
  67. package/base-modules/rbac/form.js +2 -1
  68. package/base-modules/rbac/more-actions.d.ts +0 -5
  69. package/base-modules/rbac/more-actions.js +3 -1
  70. package/base-modules/rbac/validate.d.ts +3 -0
  71. package/base-modules/rbac/validate.js +7 -1
  72. package/base-modules/rbac/view.js +7 -5
  73. package/base-modules/school/drawer.js +3 -1
  74. package/base-modules/school/form.js +2 -1
  75. package/base-modules/school/validate.d.ts +8 -0
  76. package/base-modules/school/validate.js +17 -6
  77. package/base-modules/school/view.js +2 -2
  78. package/base-modules/section/filter.js +1 -1
  79. package/base-modules/section/form.js +3 -2
  80. package/base-modules/section/page.d.ts +8 -8
  81. package/base-modules/section/page.js +25 -25
  82. package/base-modules/section/validate.d.ts +7 -0
  83. package/base-modules/section/validate.js +15 -5
  84. package/base-modules/section/view.js +3 -3
  85. package/base-modules/student-fee/filter.js +1 -1
  86. package/base-modules/student-fee/form.js +3 -2
  87. package/base-modules/student-fee/more-actions.js +11 -10
  88. package/base-modules/student-fee/page.d.ts +13 -13
  89. package/base-modules/student-fee/page.js +40 -40
  90. package/base-modules/student-fee/validate.d.ts +11 -3
  91. package/base-modules/student-fee/validate.js +20 -12
  92. package/base-modules/student-fee/view.js +4 -4
  93. package/base-modules/student-profile/context/use-student-profile-module.js +2 -2
  94. package/base-modules/student-profile/filter.js +2 -2
  95. package/base-modules/student-profile/form.js +6 -5
  96. package/base-modules/student-profile/page.d.ts +10 -10
  97. package/base-modules/student-profile/page.js +31 -31
  98. package/base-modules/student-profile/validate.d.ts +8 -2
  99. package/base-modules/student-profile/validate.js +13 -10
  100. package/base-modules/student-profile/view.js +2 -2
  101. package/base-modules/subject/filter.js +1 -1
  102. package/base-modules/subject/form.js +2 -1
  103. package/base-modules/subject/more-actions.js +3 -3
  104. package/base-modules/subject/page.d.ts +9 -9
  105. package/base-modules/subject/page.js +28 -28
  106. package/base-modules/subject/validate.d.ts +12 -1
  107. package/base-modules/subject/validate.js +24 -10
  108. package/base-modules/subject/view.js +3 -3
  109. package/base-modules/teacher/context.js +3 -3
  110. package/base-modules/teacher/filter.js +1 -1
  111. package/base-modules/teacher/form.js +9 -32
  112. package/base-modules/teacher/more-actions.js +2 -2
  113. package/base-modules/teacher/page.d.ts +10 -10
  114. package/base-modules/teacher/page.js +31 -31
  115. package/base-modules/teacher/validate.d.ts +5 -1
  116. package/base-modules/teacher/validate.js +10 -25
  117. package/base-modules/teacher/view.js +3 -3
  118. package/base-modules/user/filter.js +1 -1
  119. package/base-modules/user/form.js +3 -2
  120. package/base-modules/user/page.d.ts +9 -9
  121. package/base-modules/user/page.js +28 -28
  122. package/base-modules/user/validate.d.ts +8 -1
  123. package/base-modules/user/validate.js +16 -6
  124. package/base-modules/user/view.js +1 -1
  125. package/base-modules/workspace/context.js +3 -3
  126. package/base-modules/workspace/drawer.js +1 -1
  127. package/base-modules/workspace/filter.js +1 -1
  128. package/base-modules/workspace/form.js +2 -1
  129. package/base-modules/workspace/more-actions.js +1 -1
  130. package/base-modules/workspace/page.d.ts +1 -1
  131. package/base-modules/workspace/page.js +2 -2
  132. package/base-modules/workspace/validate.d.ts +4 -0
  133. package/base-modules/workspace/validate.js +6 -2
  134. package/base-modules/workspace/view.js +2 -2
  135. package/base-modules/workspace-user/context.js +6 -6
  136. package/base-modules/workspace-user/form.js +2 -1
  137. package/base-modules/workspace-user/page.d.ts +9 -9
  138. package/base-modules/workspace-user/page.js +28 -28
  139. package/base-modules/workspace-user/validate.d.ts +4 -5
  140. package/base-modules/workspace-user/validate.js +6 -10
  141. package/base-modules/workspace-user/view.js +1 -1
  142. package/constants.d.ts +5 -1
  143. package/constants.js +2 -0
  144. package/package.json +1 -1
  145. package/tsconfig.build.tsbuildinfo +1 -1
  146. package/utils/get-translated-error.d.ts +5 -0
  147. package/utils/get-translated-error.js +5 -0
@@ -55,20 +55,20 @@ const createComponentInstances = () => ({
55
55
  moreActions: _jsx(TeacherMoreActions, {}),
56
56
  view: _jsx(TeacherView, {}),
57
57
  });
58
- const createTeacherConfig = ({ cancelLabel, dispatch, drawerFilterDescription, drawerFilterTitle, drawerFormDescription, drawerFormTitle, drawerMoreActionsDescription, drawerMoreActionsTitle, drawerViewDescription, drawerViewTitle, labelActions, labelEnabled, labelId, labelName, labelPhone, labelSpecialization, labelTeacherCode, saveLabel, searchPlaceholder, tableDescription, tableTitle, }) => {
58
+ const createTeacherConfig = ({ dispatch, drawerButtonCancel, drawerButtonSave, drawerFilterDescription, drawerFilterTitle, drawerFormDescription, drawerFormTitle, drawerMoreActionsDescription, drawerMoreActionsTitle, drawerViewDescription, drawerViewTitle, tableColumnHeaderActions, tableColumnHeaderEnabled, tableColumnHeaderId, tableColumnHeaderName, tableColumnHeaderPhone, tableColumnHeaderSpecialization, tableColumnHeaderTeacherCode, tableDescription, tableSearchPlaceholder, tableTitle, }) => {
59
59
  const components = createComponentInstances();
60
60
  return {
61
61
  moduleName: "teacher",
62
62
  tableColumns: [
63
- { label: labelId, width: "5%" },
64
- { label: labelTeacherCode, width: "10%" },
65
- { label: labelName, width: "30%" },
66
- { label: labelPhone, width: "25%" },
67
- { label: labelSpecialization, width: "20%" },
68
- { label: labelEnabled, width: "5%" },
69
- { label: labelActions, width: "5%" },
63
+ { label: tableColumnHeaderId, width: "5%" },
64
+ { label: tableColumnHeaderTeacherCode, width: "10%" },
65
+ { label: tableColumnHeaderName, width: "30%" },
66
+ { label: tableColumnHeaderPhone, width: "25%" },
67
+ { label: tableColumnHeaderSpecialization, width: "20%" },
68
+ { label: tableColumnHeaderEnabled, width: "5%" },
69
+ { label: tableColumnHeaderActions, width: "5%" },
70
70
  ],
71
- cancelLabel,
71
+ cancelLabel: drawerButtonCancel,
72
72
  drawerFilterDescription,
73
73
  drawerFilterTitle,
74
74
  drawerFormDescription,
@@ -80,8 +80,8 @@ const createTeacherConfig = ({ cancelLabel, dispatch, drawerFilterDescription, d
80
80
  filterContent: components.filter,
81
81
  formContent: components.form,
82
82
  moreActionsContent: components.moreActions,
83
- saveLabel,
84
- searchPlaceholder,
83
+ saveLabel: drawerButtonSave,
84
+ searchPlaceholder: tableSearchPlaceholder,
85
85
  tableDescription,
86
86
  tableTitle,
87
87
  viewContent: components.view,
@@ -98,7 +98,8 @@ const TeacherPageInner = (props) => {
98
98
  const context = useTeacherModule();
99
99
  const teacherConfig = useMemo(() => createTeacherConfig({
100
100
  dispatch: context.dispatch,
101
- cancelLabel: props.cancelLabel,
101
+ drawerButtonCancel: props.drawerButtonCancel,
102
+ drawerButtonSave: props.drawerButtonSave,
102
103
  drawerFormTitle: props.drawerFormTitle,
103
104
  drawerFormDescription: props.drawerFormDescription,
104
105
  drawerViewTitle: props.drawerViewTitle,
@@ -107,20 +108,20 @@ const TeacherPageInner = (props) => {
107
108
  drawerFilterDescription: props.drawerFilterDescription,
108
109
  drawerMoreActionsTitle: props.drawerMoreActionsTitle,
109
110
  drawerMoreActionsDescription: props.drawerMoreActionsDescription,
110
- labelActions: props.labelActions,
111
- labelEnabled: props.labelEnabled,
112
- labelId: props.labelId,
113
- labelName: props.labelName,
114
- labelPhone: props.labelPhone,
115
- labelSpecialization: props.labelSpecialization,
116
- labelTeacherCode: props.labelTeacherCode,
117
- saveLabel: props.saveLabel,
118
- searchPlaceholder: props.searchPlaceholder,
111
+ tableColumnHeaderActions: props.tableColumnHeaderActions,
112
+ tableColumnHeaderEnabled: props.tableColumnHeaderEnabled,
113
+ tableColumnHeaderId: props.tableColumnHeaderId,
114
+ tableColumnHeaderName: props.tableColumnHeaderName,
115
+ tableColumnHeaderPhone: props.tableColumnHeaderPhone,
116
+ tableColumnHeaderSpecialization: props.tableColumnHeaderSpecialization,
117
+ tableColumnHeaderTeacherCode: props.tableColumnHeaderTeacherCode,
119
118
  tableDescription: props.tableDescription,
119
+ tableSearchPlaceholder: props.tableSearchPlaceholder,
120
120
  tableTitle: props.tableTitle,
121
121
  }), [
122
122
  context.dispatch,
123
- props.cancelLabel,
123
+ props.drawerButtonCancel,
124
+ props.drawerButtonSave,
124
125
  props.drawerFormTitle,
125
126
  props.drawerFormDescription,
126
127
  props.drawerViewTitle,
@@ -129,16 +130,15 @@ const TeacherPageInner = (props) => {
129
130
  props.drawerFilterDescription,
130
131
  props.drawerMoreActionsTitle,
131
132
  props.drawerMoreActionsDescription,
132
- props.labelActions,
133
- props.labelEnabled,
134
- props.labelId,
135
- props.labelName,
136
- props.labelPhone,
137
- props.labelSpecialization,
138
- props.labelTeacherCode,
139
- props.saveLabel,
140
- props.searchPlaceholder,
133
+ props.tableColumnHeaderActions,
134
+ props.tableColumnHeaderEnabled,
135
+ props.tableColumnHeaderId,
136
+ props.tableColumnHeaderName,
137
+ props.tableColumnHeaderPhone,
138
+ props.tableColumnHeaderSpecialization,
139
+ props.tableColumnHeaderTeacherCode,
141
140
  props.tableDescription,
141
+ props.tableSearchPlaceholder,
142
142
  props.tableTitle,
143
143
  ]);
144
144
  const hasPermission = resolveRbacPermissions({
@@ -1,9 +1,13 @@
1
1
  /**
2
2
  * Teacher Validation Schema
3
3
  *
4
- * Zod validation schemas for teacher form data.
4
+ * Zod validation schemas for teacher form data with i18n-ready error keys.
5
5
  */
6
6
  import { z } from "zod";
7
+ export declare const VALIDATION_KEYS: {
8
+ readonly firstName: "validationTeacherFirstNameRequired";
9
+ readonly lastName: "validationTeacherLastNameRequired";
10
+ };
7
11
  export declare const teacherFormValidation: z.ZodObject<{
8
12
  address: z.ZodNullable<z.ZodOptional<z.ZodString>>;
9
13
  avatar: z.ZodNullable<z.ZodOptional<z.ZodString>>;
@@ -1,10 +1,17 @@
1
1
  /**
2
2
  * Teacher Validation Schema
3
3
  *
4
- * Zod validation schemas for teacher form data.
4
+ * Zod validation schemas for teacher form data with i18n-ready error keys.
5
5
  */
6
6
  import { z } from "zod";
7
7
  // ============================================================================
8
+ // VALIDATION KEYS
9
+ // ============================================================================
10
+ export const VALIDATION_KEYS = {
11
+ firstName: "validationTeacherFirstNameRequired",
12
+ lastName: "validationTeacherLastNameRequired",
13
+ };
14
+ // ============================================================================
8
15
  // VALIDATION SCHEMA
9
16
  // ============================================================================
10
17
  export const teacherFormValidation = z.object({
@@ -15,39 +22,17 @@ export const teacherFormValidation = z.object({
15
22
  country: z.string().optional().nullable(),
16
23
  dateOfBirth: z.string().optional().nullable(),
17
24
  emergencyPhone: z.string().nullable().optional(),
18
- // .superRefine((val, ctx) => {
19
- // if (!val) return; // null, undefined, or empty string are OK
20
- // if (
21
- // !/^([+]?[\s0-9]+)?(\d{3}|[(]?[0-9]+[)]?)?([-]?[\s]?[0-9])+$/.test(val)
22
- // ) {
23
- // ctx.addIssue({
24
- // code: z.ZodIssueCode.custom,
25
- // message: "Invalid phone number format",
26
- // });
27
- // }
28
- // }),
29
25
  campusId: z.string().optional().nullable(),
30
26
  experience: z.number().optional().nullable(),
31
- firstName: z.string().min(1, "First name is required"),
27
+ firstName: z.string().min(1, VALIDATION_KEYS.firstName),
32
28
  gender: z
33
29
  .preprocess((val) => (val === "" ? undefined : val), z
34
30
  .enum(["MALE", "FEMALE", "OTHER", "PREFER_NOT_TO_SAY"])
35
31
  .optional()
36
32
  .nullable()),
37
33
  joiningDate: z.string().optional(),
38
- lastName: z.string().min(1, "Last name is required"),
34
+ lastName: z.string().min(1, VALIDATION_KEYS.lastName),
39
35
  phone: z.string().nullable().optional(),
40
- // .superRefine((val, ctx) => {
41
- // if (!val) return; // null, undefined, or empty string are OK
42
- // if (
43
- // !/^([+]?[\s0-9]+)?(\d{3}|[(]?[0-9]+[)]?)?([-]?[\s]?[0-9])+$/.test(val)
44
- // ) {
45
- // ctx.addIssue({
46
- // code: z.ZodIssueCode.custom,
47
- // message: "Invalid phone number format",
48
- // });
49
- // }
50
- // }),
51
36
  postalCode: z.string().optional().nullable(),
52
37
  qualification: z.string().optional().nullable(),
53
38
  specialization: z.string().optional().nullable(),
@@ -22,8 +22,8 @@ export const TeacherView = () => {
22
22
  const last = (lastName === null || lastName === void 0 ? void 0 : lastName.charAt(0)) || "";
23
23
  return (first + last).toUpperCase() || "T";
24
24
  };
25
- return (_jsxs("div", { className: "space-y-4", children: [_jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(User, { className: "text-primary h-5 w-5" }), _jsx(CardTitle, { className: "text-lg", children: t("viewSectionBasicInformation") })] }), _jsx(CardDescription, { children: t("viewSectionTeachersPersonalDetails") })] }), _jsx(Separator, {}), _jsx(CardContent, { className: "pt-6", children: _jsxs("div", { className: "grid grid-cols-1 gap-6", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldProfilePicture") }), _jsxs(Avatar, { className: "h-20 w-20", children: [_jsx(AvatarImage, { src: avatar || undefined, alt: fullName }), _jsx(AvatarFallback, { className: "text-lg", children: getInitials() })] })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldTeacherCode") }), _jsx("p", { className: "font-mono text-base", children: formatValue(teacherCode) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldName") }), _jsx("p", { className: "text-base", children: fullName })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldGender") }), _jsx("p", { className: "text-base", children: formatValue(gender) })] }), _jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Calendar, { className: "text-muted-foreground h-4 w-4" }), _jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldDateOfBirth") })] }), _jsx("p", { className: "text-base", children: formatDateValue(dateOfBirth) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldStatus") }), _jsx("div", { className: "flex items-center gap-2", children: enabled ? (_jsxs(_Fragment, { children: [_jsx(CheckCircle2, { className: "h-4 w-4 text-green-600" }), _jsx(Badge, { variant: "default", children: t("badgeActive") })] })) : (_jsxs(_Fragment, { children: [_jsx(XCircle, { className: "h-4 w-4 text-red-600" }), _jsx(Badge, { variant: "destructive", children: t("badgeInactive") })] })) })] })] }) })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Phone, { className: "text-primary h-5 w-5" }), _jsx(CardTitle, { className: "text-lg", children: t("viewSectionContactInformation") })] }), _jsx(CardDescription, { children: t("viewFieldHowToReachTheTeacher") })] }), _jsx(Separator, {}), _jsx(CardContent, { className: "pt-6", children: _jsxs("div", { className: "grid grid-cols-1 gap-6", children: [_jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Phone, { className: "text-muted-foreground h-4 w-4" }), _jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldPhone") })] }), _jsx("p", { className: "text-base", children: formatPhoneDisplay(phone) || formatValue(phone) })] }), _jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Phone, { className: "text-muted-foreground h-4 w-4" }), _jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldEmergencyPhone") })] }), _jsx("p", { className: "text-base", children: formatPhoneDisplay(emergencyPhone) ||
26
- formatValue(emergencyPhone) })] })] }) })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(GraduationCap, { className: "text-primary h-5 w-5" }), _jsx(CardTitle, { className: "text-lg", children: t("viewSectionProfessionalInformation") })] }), _jsx(CardDescription, { children: t("viewFieldTeachingCredentialsAndExperience") })] }), _jsx(Separator, {}), _jsx(CardContent, { className: "pt-6", children: _jsxs("div", { className: "grid grid-cols-1 gap-6", children: [_jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldQualification") }), _jsx("p", { className: "text-base", children: formatValue(qualification) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldSpecialization") }), _jsx("p", { className: "text-base", children: formatValue(specialization) })] }), _jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Briefcase, { className: "text-muted-foreground h-4 w-4" }), _jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldExperience") })] }), _jsx("p", { className: "text-base", children: experience
25
+ return (_jsxs("div", { className: "space-y-4", children: [_jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(User, { className: "text-primary h-5 w-5" }), _jsx(CardTitle, { className: "text-lg", children: t("viewSectionBasicInformation") })] }), _jsx(CardDescription, { children: t("viewSectionTeachersPersonalDetails") })] }), _jsx(Separator, {}), _jsx(CardContent, { className: "pt-6", children: _jsxs("div", { className: "grid grid-cols-1 gap-6", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldProfilePicture") }), _jsxs(Avatar, { className: "h-20 w-20", children: [_jsx(AvatarImage, { src: avatar || undefined, alt: fullName }), _jsx(AvatarFallback, { className: "text-lg", children: getInitials() })] })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldTeacherCode") }), _jsx("p", { className: "font-mono text-base", children: formatValue(teacherCode) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldName") }), _jsx("p", { className: "text-base", children: fullName })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("formGenderLabel") }), _jsx("p", { className: "text-base", children: formatValue(gender) })] }), _jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Calendar, { className: "text-muted-foreground h-4 w-4" }), _jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("formDateOfBirthLabel") })] }), _jsx("p", { className: "text-base", children: formatDateValue(dateOfBirth) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldStatus") }), _jsx("div", { className: "flex items-center gap-2", children: enabled ? (_jsxs(_Fragment, { children: [_jsx(CheckCircle2, { className: "h-4 w-4 text-green-600" }), _jsx(Badge, { variant: "default", children: t("badgeActive") })] })) : (_jsxs(_Fragment, { children: [_jsx(XCircle, { className: "h-4 w-4 text-red-600" }), _jsx(Badge, { variant: "destructive", children: t("badgeInactive") })] })) })] })] }) })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Phone, { className: "text-primary h-5 w-5" }), _jsx(CardTitle, { className: "text-lg", children: t("viewSectionContactInformation") })] }), _jsx(CardDescription, { children: t("viewFieldHowToReachTheTeacher") })] }), _jsx(Separator, {}), _jsx(CardContent, { className: "pt-6", children: _jsxs("div", { className: "grid grid-cols-1 gap-6", children: [_jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Phone, { className: "text-muted-foreground h-4 w-4" }), _jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldPhone") })] }), _jsx("p", { className: "text-base", children: formatPhoneDisplay(phone) || formatValue(phone) })] }), _jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Phone, { className: "text-muted-foreground h-4 w-4" }), _jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("formEmergencyPhoneLabel") })] }), _jsx("p", { className: "text-base", children: formatPhoneDisplay(emergencyPhone) ||
26
+ formatValue(emergencyPhone) })] })] }) })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(GraduationCap, { className: "text-primary h-5 w-5" }), _jsx(CardTitle, { className: "text-lg", children: t("viewSectionProfessionalInformation") })] }), _jsx(CardDescription, { children: t("viewFieldTeachingCredentialsAndExperience") })] }), _jsx(Separator, {}), _jsx(CardContent, { className: "pt-6", children: _jsxs("div", { className: "grid grid-cols-1 gap-6", children: [_jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("formQualificationLabel") }), _jsx("p", { className: "text-base", children: formatValue(qualification) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("formSpecializationLabel") }), _jsx("p", { className: "text-base", children: formatValue(specialization) })] }), _jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Briefcase, { className: "text-muted-foreground h-4 w-4" }), _jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldExperience") })] }), _jsx("p", { className: "text-base", children: experience
27
27
  ? t("experienceYears", { years: experience })
28
- : "\u2014" })] }), _jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Calendar, { className: "text-muted-foreground h-4 w-4" }), _jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldJoiningDate") })] }), _jsx("p", { className: "text-base", children: formatDateValue(joiningDate) })] })] }) })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(MapPin, { className: "text-primary h-5 w-5" }), _jsx(CardTitle, { className: "text-lg", children: t("viewSectionAddressInformation") })] }), _jsx(CardDescription, { children: t("viewFieldTeachersResidentialAddress") })] }), _jsx(Separator, {}), _jsx(CardContent, { className: "pt-6", children: _jsxs("div", { className: "grid grid-cols-1 gap-6", children: [_jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldAddress") }), _jsx("p", { className: "text-base", children: formatValue(address) })] }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldCity") }), _jsx("p", { className: "text-base", children: formatValue(city) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldStateProvince") }), _jsx("p", { className: "text-base", children: formatValue(stateValue) })] })] }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldCountry") }), _jsx("p", { className: "text-base", children: formatValue(country) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldPostalCode") }), _jsx("p", { className: "text-base", children: formatValue(postalCode) })] })] })] }) })] }), bio && (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsx(CardTitle, { className: "text-lg", children: t("viewFieldBiography") }), _jsx(CardDescription, { children: t("viewFieldAboutTheTeacher") })] }), _jsx(Separator, {}), _jsx(CardContent, { className: "pt-6", children: _jsx("p", { className: "text-base", children: bio }) })] }))] }));
28
+ : "\u2014" })] }), _jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Calendar, { className: "text-muted-foreground h-4 w-4" }), _jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("formJoiningDateLabel") })] }), _jsx("p", { className: "text-base", children: formatDateValue(joiningDate) })] })] }) })] }), _jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(MapPin, { className: "text-primary h-5 w-5" }), _jsx(CardTitle, { className: "text-lg", children: t("viewSectionAddressInformation") })] }), _jsx(CardDescription, { children: t("viewFieldTeachersResidentialAddress") })] }), _jsx(Separator, {}), _jsx(CardContent, { className: "pt-6", children: _jsxs("div", { className: "grid grid-cols-1 gap-6", children: [_jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("formAddressLabel") }), _jsx("p", { className: "text-base", children: formatValue(address) })] }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("formCityLabel") }), _jsx("p", { className: "text-base", children: formatValue(city) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldStateProvince") }), _jsx("p", { className: "text-base", children: formatValue(stateValue) })] })] }), _jsxs("div", { className: "grid grid-cols-2 gap-4", children: [_jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("formCountryLabel") }), _jsx("p", { className: "text-base", children: formatValue(country) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("formPostalCodeLabel") }), _jsx("p", { className: "text-base", children: formatValue(postalCode) })] })] })] }) })] }), bio && (_jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsx(CardTitle, { className: "text-lg", children: t("viewFieldBiography") }), _jsx(CardDescription, { children: t("viewFieldAboutTheTeacher") })] }), _jsx(Separator, {}), _jsx(CardContent, { className: "pt-6", children: _jsx("p", { className: "text-base", children: bio }) })] }))] }));
29
29
  };
@@ -12,7 +12,7 @@ export const UserFilter = () => {
12
12
  : filterEnabled
13
13
  ? "true"
14
14
  : "false";
15
- return (_jsx("div", { className: "space-y-4", children: _jsx("div", { className: "grid grid-cols-1 gap-4", children: _jsx(EnhancedRadio, { label: t("filterOptionEnabled"), name: "filterEnabled", value: filterEnabledValue, options: [
15
+ return (_jsx("div", { className: "space-y-4", children: _jsx("div", { className: "grid grid-cols-1 gap-4", children: _jsx(EnhancedRadio, { label: t("filterEnabledLabel"), name: "filterEnabled", value: filterEnabledValue, options: [
16
16
  { label: t("filterOptionAll"), value: "undefined" },
17
17
  { label: t("filterOptionEnabled"), value: "true" },
18
18
  { label: t("filterOptionDisabled"), value: "false" },
@@ -11,6 +11,7 @@ import { USER_API_ROUTES } from "../../constants";
11
11
  import { formatPhone } from "@react-pakistan/util-functions/general/format-phone";
12
12
  import { useState } from "react";
13
13
  import { Eye, EyeOff } from "lucide-react";
14
+ import { getTranslatedError } from "../../utils/get-translated-error";
14
15
  export const UserForm = () => {
15
16
  const t = useTranslations("user");
16
17
  const { handleAvatar, handleChange, state } = useUserModule();
@@ -52,8 +53,8 @@ export const UserForm = () => {
52
53
  },
53
54
  value: userRole !== null && userRole !== void 0 ? userRole : "",
54
55
  });
55
- return (_jsxs("div", { className: "space-y-4", children: [_jsx(EnhancedInput, { error: errors.name, id: "name", info: t("formNameInfo"), label: t("formNameLabel"), onChange: (e) => handleChange("name", e.target.value), placeholder: t("formNamePlaceholder"), required: true, value: name || "" }), _jsx(EnhancedInput, { error: errors.email, id: "email", info: t("formEmailInfo"), label: t("formEmailLabel"), onChange: (e) => handleChange("email", e.target.value), placeholder: t("formEmailPlaceholder"), required: true, type: "email", value: email }), _jsxs("div", { className: "relative", children: [_jsx(EnhancedInput, { error: errors.password, id: "password", info: t("formPasswordInfo"), label: t("formPasswordLabel"), onChange: (e) => handleChange("password", e.target.value), placeholder: t("formPasswordPlaceholder"), type: passwordVisible ? "text" : "password", value: password || "" }), _jsx("button", { type: "button", "aria-label": passwordVisible ? t("actionHidePassword") : t("actionShowPassword"), onClick: () => setPasswordVisible(!passwordVisible), className: "text-muted-foreground hover:text-foreground absolute inset-y-0 top-1 right-3 flex items-center justify-center p-1 text-sm", children: passwordVisible ? (_jsx(EyeOff, { className: "h-4 w-4" })) : (_jsx(Eye, { className: "h-4 w-4" })) })] }), _jsx(EnhancedInput, { error: errors.phone, id: "phone", info: t("formPhoneInfo"), label: t("formPhoneLabel"), onChange: (e) => {
56
+ return (_jsxs("div", { className: "space-y-4", children: [_jsx(EnhancedInput, { error: getTranslatedError({ errors, key: "name", t }), id: "name", info: t("formNameInfo"), label: t("formNameLabel"), onChange: (e) => handleChange("name", e.target.value), placeholder: t("formNamePlaceholder"), required: true, value: name || "" }), _jsx(EnhancedInput, { error: getTranslatedError({ errors, key: "email", t }), id: "email", info: t("formEmailInfo"), label: t("formEmailLabel"), onChange: (e) => handleChange("email", e.target.value), placeholder: t("formEmailPlaceholder"), required: true, type: "email", value: email }), _jsxs("div", { className: "relative", children: [_jsx(EnhancedInput, { error: getTranslatedError({ errors, key: "password", t }), id: "password", info: t("formPasswordInfo"), label: t("formPasswordLabel"), onChange: (e) => handleChange("password", e.target.value), placeholder: t("formPasswordPlaceholder"), type: passwordVisible ? "text" : "password", value: password || "" }), _jsx("button", { type: "button", "aria-label": passwordVisible ? t("actionHidePassword") : t("actionShowPassword"), onClick: () => setPasswordVisible(!passwordVisible), className: "text-muted-foreground hover:text-foreground absolute inset-y-0 top-1 right-3 flex items-center justify-center p-1 text-sm", children: passwordVisible ? (_jsx(EyeOff, { className: "h-4 w-4" })) : (_jsx(Eye, { className: "h-4 w-4" })) })] }), _jsx(EnhancedInput, { error: getTranslatedError({ errors, key: "phone", t }), id: "phone", info: t("formPhoneInfo"), label: t("formPhoneLabel"), onChange: (e) => {
56
57
  var _a;
57
58
  return handleChange("phone", ((_a = formatPhone(e.target.value)) === null || _a === void 0 ? void 0 : _a.international) || e.target.value);
58
- }, placeholder: t("formPhonePlaceholder"), type: "tel", value: phone || "" }), _jsx(EnhancedDropzone, { accept: ["image/*"], error: errors.avatar, id: "avatar", info: t("formAvatarInfo"), label: t("formAvatarLabel"), maxFiles: 1, maxSize: 0.25 * 1024 * 1024, onChange: handleAvatar, onRemoveRemote: () => handleChange("avatar", ""), resize: true, value: avatar ? [avatar] : [] }), _jsx(EnhancedCheckbox, { checked: enabled, error: errors.enabled, id: "enabled", info: t("formEnabledInfo"), label: t("formActiveUserLabel"), onCheckedChange: (checked) => handleChange("enabled", checked) }), userRoleCombo] }));
59
+ }, placeholder: t("formPhonePlaceholder"), type: "tel", value: phone || "" }), _jsx(EnhancedDropzone, { accept: ["image/*"], error: getTranslatedError({ errors, key: "avatar", t }), id: "avatar", info: t("formAvatarInfo"), label: t("formAvatarLabel"), maxFiles: 1, maxSize: 0.25 * 1024 * 1024, onChange: handleAvatar, onRemoveRemote: () => handleChange("avatar", ""), resize: true, value: avatar ? [avatar] : [] }), _jsx(EnhancedCheckbox, { checked: enabled, error: getTranslatedError({ errors, key: "enabled", t }), id: "enabled", info: t("formEnabledInfo"), label: t("formEnabledLabel"), onCheckedChange: (checked) => handleChange("enabled", checked) }), userRoleCombo] }));
59
60
  };
@@ -18,7 +18,8 @@
18
18
  import { FC } from "react";
19
19
  import { USER_ROLE } from "../../type";
20
20
  interface Props {
21
- cancelLabel: string;
21
+ drawerButtonCancel: string;
22
+ drawerButtonSave: string;
22
23
  drawerFilterDescription: string;
23
24
  drawerFilterTitle: string;
24
25
  drawerFormDescription: string;
@@ -27,15 +28,14 @@ interface Props {
27
28
  drawerMoreActionsTitle: string;
28
29
  drawerViewDescription: string;
29
30
  drawerViewTitle: string;
30
- labelActions: string;
31
- labelEmail: string;
32
- labelEnabled: string;
33
- labelId: string;
34
- labelName: string;
35
- labelPhone: string;
36
- saveLabel: string;
37
- searchPlaceholder: string;
31
+ tableColumnHeaderActions: string;
32
+ tableColumnHeaderEmail: string;
33
+ tableColumnHeaderEnabled: string;
34
+ tableColumnHeaderId: string;
35
+ tableColumnHeaderName: string;
36
+ tableColumnHeaderPhone: string;
38
37
  tableDescription: string;
38
+ tableSearchPlaceholder: string;
39
39
  tableTitle: string;
40
40
  userRole: USER_ROLE;
41
41
  }
@@ -47,19 +47,19 @@ const createComponentInstances = () => ({
47
47
  moreActions: _jsx(UserMoreActions, {}),
48
48
  view: _jsx(UserView, {}),
49
49
  });
50
- const createUserConfig = ({ cancelLabel, dispatch, drawerFilterDescription, drawerFilterTitle, drawerFormDescription, drawerFormTitle, drawerMoreActionsDescription, drawerMoreActionsTitle, drawerViewDescription, drawerViewTitle, labelActions, labelEmail, labelEnabled, labelId, labelName, labelPhone, saveLabel, searchPlaceholder, tableDescription, tableTitle, }) => {
50
+ const createUserConfig = ({ dispatch, drawerButtonCancel, drawerButtonSave, drawerFilterDescription, drawerFilterTitle, drawerFormDescription, drawerFormTitle, drawerMoreActionsDescription, drawerMoreActionsTitle, drawerViewDescription, drawerViewTitle, tableColumnHeaderActions, tableColumnHeaderEmail, tableColumnHeaderEnabled, tableColumnHeaderId, tableColumnHeaderName, tableColumnHeaderPhone, tableDescription, tableSearchPlaceholder, tableTitle, }) => {
51
51
  const components = createComponentInstances();
52
52
  return {
53
53
  moduleName: "user",
54
54
  tableColumns: [
55
- { label: labelId, width: "5%" },
56
- { label: labelName, width: "30%" },
57
- { label: labelEmail, width: "30%" },
58
- { label: labelPhone, width: "20%" },
59
- { label: labelEnabled, width: "10%" },
60
- { label: labelActions, width: "5%" },
55
+ { label: tableColumnHeaderId, width: "5%" },
56
+ { label: tableColumnHeaderName, width: "30%" },
57
+ { label: tableColumnHeaderEmail, width: "30%" },
58
+ { label: tableColumnHeaderPhone, width: "20%" },
59
+ { label: tableColumnHeaderEnabled, width: "10%" },
60
+ { label: tableColumnHeaderActions, width: "5%" },
61
61
  ],
62
- cancelLabel,
62
+ cancelLabel: drawerButtonCancel,
63
63
  drawerFilterDescription,
64
64
  drawerFilterTitle,
65
65
  drawerFormDescription,
@@ -71,8 +71,8 @@ const createUserConfig = ({ cancelLabel, dispatch, drawerFilterDescription, draw
71
71
  filterContent: components.filter,
72
72
  formContent: components.form,
73
73
  moreActionsContent: components.moreActions,
74
- saveLabel,
75
- searchPlaceholder,
74
+ saveLabel: drawerButtonSave,
75
+ searchPlaceholder: tableSearchPlaceholder,
76
76
  tableDescription,
77
77
  tableTitle,
78
78
  viewContent: components.view,
@@ -89,7 +89,8 @@ const UserPageInner = (props) => {
89
89
  const context = useUserModule();
90
90
  const userConfig = useMemo(() => createUserConfig({
91
91
  dispatch: context.dispatch,
92
- cancelLabel: props.cancelLabel,
92
+ drawerButtonCancel: props.drawerButtonCancel,
93
+ drawerButtonSave: props.drawerButtonSave,
93
94
  drawerFormTitle: props.drawerFormTitle,
94
95
  drawerFormDescription: props.drawerFormDescription,
95
96
  drawerViewTitle: props.drawerViewTitle,
@@ -98,19 +99,19 @@ const UserPageInner = (props) => {
98
99
  drawerFilterDescription: props.drawerFilterDescription,
99
100
  drawerMoreActionsTitle: props.drawerMoreActionsTitle,
100
101
  drawerMoreActionsDescription: props.drawerMoreActionsDescription,
101
- labelActions: props.labelActions,
102
- labelEmail: props.labelEmail,
103
- labelEnabled: props.labelEnabled,
104
- labelId: props.labelId,
105
- labelName: props.labelName,
106
- labelPhone: props.labelPhone,
107
- saveLabel: props.saveLabel,
108
- searchPlaceholder: props.searchPlaceholder,
102
+ tableColumnHeaderActions: props.tableColumnHeaderActions,
103
+ tableColumnHeaderEmail: props.tableColumnHeaderEmail,
104
+ tableColumnHeaderEnabled: props.tableColumnHeaderEnabled,
105
+ tableColumnHeaderId: props.tableColumnHeaderId,
106
+ tableColumnHeaderName: props.tableColumnHeaderName,
107
+ tableColumnHeaderPhone: props.tableColumnHeaderPhone,
109
108
  tableDescription: props.tableDescription,
109
+ tableSearchPlaceholder: props.tableSearchPlaceholder,
110
110
  tableTitle: props.tableTitle,
111
111
  }), [
112
112
  context.dispatch,
113
- props.cancelLabel,
113
+ props.drawerButtonCancel,
114
+ props.drawerButtonSave,
114
115
  props.drawerFormTitle,
115
116
  props.drawerFormDescription,
116
117
  props.drawerViewTitle,
@@ -119,15 +120,14 @@ const UserPageInner = (props) => {
119
120
  props.drawerFilterDescription,
120
121
  props.drawerMoreActionsTitle,
121
122
  props.drawerMoreActionsDescription,
122
- props.labelActions,
123
- props.labelEmail,
124
- props.labelEnabled,
125
- props.labelId,
126
- props.labelName,
127
- props.labelPhone,
128
- props.saveLabel,
129
- props.searchPlaceholder,
123
+ props.tableColumnHeaderActions,
124
+ props.tableColumnHeaderEmail,
125
+ props.tableColumnHeaderEnabled,
126
+ props.tableColumnHeaderId,
127
+ props.tableColumnHeaderName,
128
+ props.tableColumnHeaderPhone,
130
129
  props.tableDescription,
130
+ props.tableSearchPlaceholder,
131
131
  props.tableTitle,
132
132
  ]);
133
133
  const hasPermission = resolveRbacPermissions({
@@ -1,10 +1,17 @@
1
1
  /**
2
2
  * User Validation Schema
3
3
  *
4
- * Zod validation schemas for user form data.
4
+ * Zod validation schemas for user form data with i18n-ready error keys.
5
5
  */
6
6
  import { z } from "zod";
7
7
  import { USER_ROLE } from "../../type";
8
+ export declare const VALIDATION_KEYS: {
9
+ readonly name: "validationUserNameRequired";
10
+ readonly emailInvalid: "validationUserEmailInvalid";
11
+ readonly phoneInvalid: "validationUserPhoneInvalid";
12
+ readonly roleInvalid: "validationUserRoleInvalid";
13
+ readonly roleSchoolAdminNotAllowed: "validationUserRoleSchoolAdminNotAllowed";
14
+ };
8
15
  export declare const userFormValidation: z.ZodObject<{
9
16
  name: z.ZodString;
10
17
  email: z.ZodEmail;
@@ -1,29 +1,39 @@
1
1
  /**
2
2
  * User Validation Schema
3
3
  *
4
- * Zod validation schemas for user form data.
4
+ * Zod validation schemas for user form data with i18n-ready error keys.
5
5
  */
6
6
  import { z } from "zod";
7
7
  import { USER_ROLE } from "../../type";
8
8
  // ============================================================================
9
+ // VALIDATION KEYS
10
+ // ============================================================================
11
+ export const VALIDATION_KEYS = {
12
+ name: "validationUserNameRequired",
13
+ emailInvalid: "validationUserEmailInvalid",
14
+ phoneInvalid: "validationUserPhoneInvalid",
15
+ roleInvalid: "validationUserRoleInvalid",
16
+ roleSchoolAdminNotAllowed: "validationUserRoleSchoolAdminNotAllowed",
17
+ };
18
+ // ============================================================================
9
19
  // VALIDATION SCHEMA
10
20
  // ============================================================================
11
21
  export const userFormValidation = z.object({
12
- name: z.string().min(1, "Name is required"),
13
- email: z.email("Invalid email address"),
22
+ name: z.string().min(1, VALIDATION_KEYS.name),
23
+ email: z.email(VALIDATION_KEYS.emailInvalid),
14
24
  password: z.string().optional(),
15
25
  phone: z
16
26
  .string()
17
27
  .optional()
18
28
  .refine((val) => !val ||
19
- /^([+]?[\s0-9]+)?(\d{3}|[(]?[0-9]+[)]?)?([-]?[\s]?[0-9])+$/.test(val), "Invalid phone number format"),
29
+ /^([+]?[\s0-9]+)?(\d{3}|[(]?[0-9]+[)]?)?([-]?[\s]?[0-9])+$/.test(val), VALIDATION_KEYS.phoneInvalid),
20
30
  avatar: z.string().optional(),
21
31
  enabled: z.boolean().optional(),
22
32
  userRole: z
23
33
  .nativeEnum(USER_ROLE, {
24
- error: "Invalid or missing role",
34
+ error: VALIDATION_KEYS.roleInvalid,
25
35
  })
26
36
  .refine((v) => v !== USER_ROLE.SCHOOL_ADMIN, {
27
- message: "Selecting SCHOOL_ADMIN is not allowed",
37
+ message: VALIDATION_KEYS.roleSchoolAdminNotAllowed,
28
38
  }),
29
39
  });
@@ -23,5 +23,5 @@ export const UserView = () => {
23
23
  const t = useTranslations("user");
24
24
  const { state } = useUserModule();
25
25
  const { avatar, email, enabled, name, phone } = state;
26
- return (_jsx("div", { className: "space-y-4", children: _jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(User, { className: "text-primary h-5 w-5" }), _jsx(CardTitle, { className: "text-lg", children: t("viewFieldUserInformation") })] }), _jsx(CardDescription, { children: t("viewUserAccountDetails") })] }), _jsx(Separator, {}), _jsx(CardContent, { className: "pt-6", children: _jsxs("div", { className: "grid grid-cols-1 gap-6", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldProfilePicture") }), _jsxs(Avatar, { className: "h-20 w-20", children: [_jsx(AvatarImage, { src: avatar || undefined, alt: name || t("viewFieldName") }), _jsx(AvatarFallback, { className: "text-lg", children: getInitials(name) })] })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldName") }), _jsx("p", { className: "text-base", children: formatValue(name) })] }), _jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Mail, { className: "text-muted-foreground h-4 w-4" }), _jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldEmailAddress") })] }), _jsx("p", { className: "text-base", children: formatValue(email) })] }), _jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Phone, { className: "text-muted-foreground h-4 w-4" }), _jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldPhoneNumber") })] }), _jsx("p", { className: "text-base", children: formatPhoneDisplay(phone) || formatValue(phone) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldStatus") }), _jsxs(Badge, { variant: enabled ? "default" : "destructive", className: "gap-1", children: [enabled ? (_jsx(CheckCircle2, { className: "h-3 w-3" })) : (_jsx(XCircle, { className: "h-3 w-3" })), enabled ? t("badgeActive") : t("badgeInactive")] })] })] }) })] }) }));
26
+ return (_jsx("div", { className: "space-y-4", children: _jsxs(Card, { children: [_jsxs(CardHeader, { className: "pb-3", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(User, { className: "text-primary h-5 w-5" }), _jsx(CardTitle, { className: "text-lg", children: t("viewFieldUserInformation") })] }), _jsx(CardDescription, { children: t("viewUserAccountDetails") })] }), _jsx(Separator, {}), _jsx(CardContent, { className: "pt-6", children: _jsxs("div", { className: "grid grid-cols-1 gap-6", children: [_jsxs("div", { className: "space-y-2", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldProfilePicture") }), _jsxs(Avatar, { className: "h-20 w-20", children: [_jsx(AvatarImage, { src: avatar || undefined, alt: name || t("viewFieldName") }), _jsx(AvatarFallback, { className: "text-lg", children: getInitials(name) })] })] }), _jsxs("div", { className: "space-y-1", children: [_jsxs("p", { className: "text-muted-foreground text-sm font-medium", children: [" ", t("formNameLabel")] }), _jsx("p", { className: "text-base", children: formatValue(name) })] }), _jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Mail, { className: "text-muted-foreground h-4 w-4" }), _jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("formEmailLabel") })] }), _jsx("p", { className: "text-base", children: formatValue(email) })] }), _jsxs("div", { className: "space-y-1", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Phone, { className: "text-muted-foreground h-4 w-4" }), _jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("formPhoneLabel") })] }), _jsx("p", { className: "text-base", children: formatPhoneDisplay(phone) || formatValue(phone) })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-muted-foreground text-sm font-medium", children: t("viewFieldStatus") }), _jsxs(Badge, { variant: enabled ? "default" : "destructive", className: "gap-1", children: [enabled ? (_jsx(CheckCircle2, { className: "h-3 w-3" })) : (_jsx(XCircle, { className: "h-3 w-3" })), enabled ? t("badgeActive") : t("badgeInactive")] })] })] }) })] }) }));
27
27
  };
@@ -101,7 +101,7 @@ export const WorkspaceStateContextProvider = ({ children, }) => {
101
101
  }
102
102
  catch (_a) {
103
103
  generateThemeToast({
104
- description: t("messagesFetchFailed"),
104
+ description: t("messagesWorkspaceFetchFailed"),
105
105
  variant: TOAST_VARIANT.ERROR,
106
106
  });
107
107
  }
@@ -203,11 +203,11 @@ export const useWorkspaceModule = () => {
203
203
  const listCallback = useCallback(() => { }, []);
204
204
  const updateCallback = useCallback(({ data, error }) => {
205
205
  if (error) {
206
- showToast(t("messagesUpdateFailed"), TOAST_VARIANT.ERROR);
206
+ showToast(t("messagesWorkspaceUpdateFailed"), TOAST_VARIANT.ERROR);
207
207
  return;
208
208
  }
209
209
  if (data) {
210
- showToast(t("messagesSaveSuccess"), TOAST_VARIANT.SUCCESS);
210
+ showToast(t("messagesWorkspaceUpdated"), TOAST_VARIANT.SUCCESS);
211
211
  invalidateWorkspaceCache();
212
212
  resetFormAndCloseDrawer();
213
213
  }
@@ -22,5 +22,5 @@ export const WorkspaceDrawer = () => {
22
22
  const isMoreActionsDrawer = drawer === WORKSPACE_DRAWER.MORE_ACTIONS_DRAWER;
23
23
  const applyFilters = () => { };
24
24
  const clearFilters = () => { };
25
- return (_jsx(DrawerGeneric, { filterDrawer: null, filterDrawerHeader: null, filterDrawerFooter: null, formDrawer: isFormDrawer ? _jsx(WorkspaceForm, {}) : null, formDrawerHeader: isFormDrawer ? (_jsx(EnhancedDrawerHeader, { title: t("formDrawerTitle"), description: t("formDrawerDescription") })) : null, formDrawerFooter: isFormDrawer ? (_jsx(EnhancedDrawerFooter, { applyFilters: applyFilters, clearFilters: clearFilters, closeDrawer: handleCloseDrawer, disableSaveButton: disableSaveButton, drawerType: DRAWER_FOOTER_COMPONENT_TYPE.FORM_DRAWER, errors: errors, handleSubmit: handleSubmit, updateLoading: updateLoading })) : null, viewDrawer: isViewDrawer ? _jsx(WorkspaceView, {}) : null, viewDrawerHeader: isViewDrawer ? (_jsx(EnhancedDrawerHeader, { title: t("viewTitle"), description: t("viewDescription") })) : null, viewDrawerFooter: isViewDrawer ? (_jsx(EnhancedDrawerFooter, { applyFilters: applyFilters, clearFilters: clearFilters, closeDrawer: handleCloseDrawer, disableSaveButton: disableSaveButton, drawerType: DRAWER_FOOTER_COMPONENT_TYPE.VIEW_DRAWER, errors: errors, handleSubmit: handleSubmit, updateLoading: updateLoading })) : null, moreActionsDrawer: isMoreActionsDrawer ? _jsx(WorkspaceMoreActions, {}) : null, moreActionsDrawerHeader: isMoreActionsDrawer ? (_jsx(EnhancedDrawerHeader, { title: t("moreActionsTitle"), description: t("moreActionsDescription") })) : null, moreActionsDrawerFooter: isMoreActionsDrawer ? (_jsx(EnhancedDrawerFooter, { applyFilters: applyFilters, clearFilters: clearFilters, closeDrawer: handleCloseDrawer, disableSaveButton: disableSaveButton, drawerType: DRAWER_FOOTER_COMPONENT_TYPE.MORE_ACTIONS_DRAWER, errors: errors, handleSubmit: handleSubmit, updateLoading: updateLoading })) : null, onOpenChange: (open) => !open && handleCloseDrawer(), open: isFormDrawer || isViewDrawer || isMoreActionsDrawer }));
25
+ return (_jsx(DrawerGeneric, { filterDrawer: null, filterDrawerHeader: null, filterDrawerFooter: null, formDrawer: isFormDrawer ? _jsx(WorkspaceForm, {}) : null, formDrawerHeader: isFormDrawer ? (_jsx(EnhancedDrawerHeader, { title: t("drawerFormTitle"), description: t("drawerFormDescription") })) : null, formDrawerFooter: isFormDrawer ? (_jsx(EnhancedDrawerFooter, { applyFilters: applyFilters, clearFilters: clearFilters, closeDrawer: handleCloseDrawer, disableSaveButton: disableSaveButton, drawerType: DRAWER_FOOTER_COMPONENT_TYPE.FORM_DRAWER, errors: errors, handleSubmit: handleSubmit, updateLoading: updateLoading })) : null, viewDrawer: isViewDrawer ? _jsx(WorkspaceView, {}) : null, viewDrawerHeader: isViewDrawer ? (_jsx(EnhancedDrawerHeader, { title: t("drawerViewTitle"), description: t("drawerViewDescription") })) : null, viewDrawerFooter: isViewDrawer ? (_jsx(EnhancedDrawerFooter, { applyFilters: applyFilters, clearFilters: clearFilters, closeDrawer: handleCloseDrawer, disableSaveButton: disableSaveButton, drawerType: DRAWER_FOOTER_COMPONENT_TYPE.VIEW_DRAWER, errors: errors, handleSubmit: handleSubmit, updateLoading: updateLoading })) : null, moreActionsDrawer: isMoreActionsDrawer ? _jsx(WorkspaceMoreActions, {}) : null, moreActionsDrawerHeader: isMoreActionsDrawer ? (_jsx(EnhancedDrawerHeader, { title: t("drawerMoreActionsTitle"), description: t("drawerMoreActionsDescription") })) : null, moreActionsDrawerFooter: isMoreActionsDrawer ? (_jsx(EnhancedDrawerFooter, { applyFilters: applyFilters, clearFilters: clearFilters, closeDrawer: handleCloseDrawer, disableSaveButton: disableSaveButton, drawerType: DRAWER_FOOTER_COMPONENT_TYPE.MORE_ACTIONS_DRAWER, errors: errors, handleSubmit: handleSubmit, updateLoading: updateLoading })) : null, onOpenChange: (open) => !open && handleCloseDrawer(), open: isFormDrawer || isViewDrawer || isMoreActionsDrawer }));
26
26
  };
@@ -9,5 +9,5 @@ import { jsx as _jsx } from "react/jsx-runtime";
9
9
  import { useTranslations } from "next-intl";
10
10
  export const WorkspaceFilter = () => {
11
11
  const t = useTranslations("workspace");
12
- return (_jsx("div", { className: "p-6 text-center text-muted-foreground", children: _jsx("p", { children: t("filterFallbackText") }) }));
12
+ return (_jsx("div", { className: "p-6 text-center text-muted-foreground", children: _jsx("p", { children: t("messagesNoFiltersAvailable") }) }));
13
13
  };
@@ -11,6 +11,7 @@ import { useTranslations } from "next-intl";
11
11
  import { EnhancedInput } from "@appcorp/shadcn/components/enhanced-input";
12
12
  import { EnhancedTextarea } from "@appcorp/shadcn/components/enhanced-textarea";
13
13
  import { useEnhancedCombobox } from "@appcorp/shadcn/hooks/use-enhanced-combobox";
14
+ import { getTranslatedError } from "@/utils/get-translated-error";
14
15
  import { Shield, Eye, EyeOff } from "lucide-react";
15
16
  import { secretKeys } from "./constants";
16
17
  import { PLAN_API_ROUTES } from "../../constants";
@@ -54,5 +55,5 @@ export const WorkspaceForm = () => {
54
55
  });
55
56
  },
56
57
  });
57
- return (_jsxs("div", { className: "space-y-6", children: [_jsx(EnhancedInput, { id: "name", label: t("formNameLabel"), value: state.name, onChange: (e) => handleChange("name", e.target.value), error: state.errors.name, placeholder: t("formNamePlaceholder"), required: true, readOnly: true }), _jsx(EnhancedInput, { id: "subdomain", label: t("formSubdomainLabel"), value: state.subdomain, onChange: (e) => handleChange("subdomain", e.target.value), error: state.errors.subdomain, placeholder: t("formSubdomainPlaceholder"), required: true, info: t("formSubdomainUrlInfo", { subdomain: state.subdomain }), readOnly: true }), _jsx(EnhancedTextarea, { id: "description", label: t("formDescriptionLabel"), value: state.description || "", onChange: (e) => handleChange("description", e.target.value), error: state.errors.description, placeholder: t("formDescriptionPlaceholder"), rows: 3 }), _jsx(EnhancedInput, { id: "logo", label: t("formLogoLabel"), value: state.logo || "", onChange: (e) => handleChange("logo", e.target.value), error: state.errors.logo, placeholder: t("formLogoPlaceholder"), type: "url", readOnly: true }), planIdCombo, _jsxs("div", { className: "mt-6 border-t pt-6", children: [_jsxs("div", { className: "mb-4 flex items-center gap-2", children: [_jsx(Shield, { className: "text-primary h-5 w-5" }), _jsx("h3", { className: "text-lg font-semibold", children: t("formSecretsTitleLabel") })] }), _jsx("p", { className: "text-muted-foreground mb-4 text-sm", children: t("formSecretsDescriptionLabel") }), _jsx(SecretsEditor, { secrets: secrets, errors: state.errors, onChange: handleSecretChange, secretPlaceholder: t("formSecretPlaceholder") })] })] }));
58
+ return (_jsxs("div", { className: "space-y-6", children: [_jsx(EnhancedInput, { id: "name", label: t("formNameLabel"), value: state.name, onChange: (e) => handleChange("name", e.target.value), error: getTranslatedError({ errors: state.errors, key: "name", t }), placeholder: t("formNamePlaceholder"), required: true, readOnly: true }), _jsx(EnhancedInput, { id: "subdomain", label: t("formSubdomainLabel"), value: state.subdomain, onChange: (e) => handleChange("subdomain", e.target.value), error: getTranslatedError({ errors: state.errors, key: "subdomain", t }), placeholder: t("formSubdomainPlaceholder"), required: true, info: t("formSubdomainUrlInfo", { subdomain: state.subdomain }), readOnly: true }), _jsx(EnhancedTextarea, { id: "description", label: t("formDescriptionLabel"), value: state.description || "", onChange: (e) => handleChange("description", e.target.value), error: state.errors.description, placeholder: t("formDescriptionPlaceholder"), rows: 3 }), _jsx(EnhancedInput, { id: "logo", label: t("formLogoLabel"), value: state.logo || "", onChange: (e) => handleChange("logo", e.target.value), error: state.errors.logo, placeholder: t("formLogoPlaceholder"), type: "url", readOnly: true }), planIdCombo, _jsxs("div", { className: "mt-6 border-t pt-6", children: [_jsxs("div", { className: "mb-4 flex items-center gap-2", children: [_jsx(Shield, { className: "text-primary h-5 w-5" }), _jsx("h3", { className: "text-lg font-semibold", children: t("formSectionSecrets") })] }), _jsx("p", { className: "text-muted-foreground mb-4 text-sm", children: t("formSecretsDescription") }), _jsx(SecretsEditor, { secrets: secrets, errors: state.errors, onChange: handleSecretChange, secretPlaceholder: t("formSecretPlaceholder") })] })] }));
58
59
  };
@@ -9,5 +9,5 @@ import { jsx as _jsx } from "react/jsx-runtime";
9
9
  import { useTranslations } from "next-intl";
10
10
  export const WorkspaceMoreActions = () => {
11
11
  const t = useTranslations("workspace");
12
- return (_jsx("div", { className: "p-6 text-center text-muted-foreground", children: _jsx("p", { children: t("moreActionsFallbackText") }) }));
12
+ return (_jsx("div", { className: "p-6 text-center text-muted-foreground", children: _jsx("p", { children: t("messagesNoAdditionalActions") }) }));
13
13
  };
@@ -12,7 +12,7 @@
12
12
  import { FC } from "react";
13
13
  import { USER_ROLE } from "../../type";
14
14
  interface Props {
15
- labelEdit: string;
15
+ actionsButtonEdit: string;
16
16
  tableDescription: string;
17
17
  tableTitle: string;
18
18
  userRole: USER_ROLE;
@@ -21,7 +21,7 @@ import { RbacNoAccess } from "../../components/rbac-no-access";
21
21
  // ============================================================================
22
22
  // INNER PAGE (requires WorkspaceStateContextProvider)
23
23
  // ============================================================================
24
- const WorkspaceInnerPage = ({ labelEdit, tableDescription, tableTitle, userRole, }) => {
24
+ const WorkspaceInnerPage = ({ actionsButtonEdit, tableDescription, tableTitle, userRole, }) => {
25
25
  const { handleEdit } = useWorkspaceModule();
26
26
  const hasPermission = resolveRbacPermissions({
27
27
  userRole,
@@ -30,7 +30,7 @@ const WorkspaceInnerPage = ({ labelEdit, tableDescription, tableTitle, userRole,
30
30
  if (!hasPermission) {
31
31
  return _jsx(RbacNoAccess, { moduleName: "Workspace" });
32
32
  }
33
- return (_jsx("div", { className: "container mx-auto px-4 py-8", children: _jsxs("div", { className: "mx-auto max-w-6xl", children: [_jsxs("div", { className: "mb-8", children: [_jsx("h1", { className: "text-3xl font-bold text-gray-900", children: tableTitle }), _jsx("p", { className: "mt-2 text-gray-600", children: tableDescription })] }), _jsx("div", { className: "mb-6 flex justify-end", children: _jsxs(Button, { onClick: handleEdit, className: "flex items-center space-x-2", children: [_jsx(Edit, { className: "h-4 w-4" }), _jsx("span", { children: labelEdit })] }) }), _jsx(WorkspaceView, {}), _jsx(WorkspaceDrawer, {})] }) }));
33
+ return (_jsx("div", { className: "container mx-auto px-4 py-8", children: _jsxs("div", { className: "mx-auto max-w-6xl", children: [_jsxs("div", { className: "mb-8", children: [_jsx("h1", { className: "text-3xl font-bold text-gray-900", children: tableTitle }), _jsx("p", { className: "mt-2 text-gray-600", children: tableDescription })] }), _jsx("div", { className: "mb-6 flex justify-end", children: _jsxs(Button, { onClick: handleEdit, className: "flex items-center space-x-2", children: [_jsx(Edit, { className: "h-4 w-4" }), _jsx("span", { children: actionsButtonEdit })] }) }), _jsx(WorkspaceView, {}), _jsx(WorkspaceDrawer, {})] }) }));
34
34
  };
35
35
  // ============================================================================
36
36
  // ROOT PAGE COMPONENT (wraps with provider)
@@ -1,4 +1,8 @@
1
1
  import { z } from "zod";
2
+ export declare const VALIDATION_KEYS: {
3
+ readonly name: "validationWorkspaceNameRequired";
4
+ readonly subdomain: "validationWorkspaceSubdomainRequired";
5
+ };
2
6
  export declare const workspaceFormValidation: z.ZodObject<{
3
7
  id: z.ZodOptional<z.ZodString>;
4
8
  name: z.ZodString;