@appcorp/fusion-storybook 0.3.45 → 0.3.46

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.
@@ -0,0 +1,152 @@
1
+ "use client";
2
+ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useMemo } from "react";
4
+ import { COMPONENT_TYPE } from "@appcorp/shadcn/components/enhanced-table";
5
+ import { createGenericModulePage, } from "@react-pakistan/util-functions/factory/generic-component-factory";
6
+ import { formatDate, DATE_FORMATS, } from "@react-pakistan/util-functions/general/format-date";
7
+ import { usePushCampaignModule, PushCampaignProvider, PUSH_CAMPAIGN_ACTION_TYPES, } from "./context";
8
+ import { PushCampaignFilter } from "./filter";
9
+ import { PushCampaignForm } from "./form";
10
+ import { PushCampaignView } from "./view";
11
+ import { resolveRbacPermissions } from "../../utils/resolve-rbac-permissions";
12
+ import { CAMPAIGN_STATUS } from "../../type";
13
+ import { RbacNoAccess } from "../../components/rbac-no-access";
14
+ const tableBodyCols = [
15
+ { componentType: COMPONENT_TYPE.ID, key: "id" },
16
+ { componentType: COMPONENT_TYPE.TEXT, key: "name" },
17
+ { componentType: COMPONENT_TYPE.TEXT, key: "title" },
18
+ {
19
+ componentType: COMPONENT_TYPE.TEXT,
20
+ key: "status",
21
+ textFormatter: (val) => {
22
+ const status = val;
23
+ const map = {
24
+ [CAMPAIGN_STATUS.DRAFT]: "Draft",
25
+ [CAMPAIGN_STATUS.SCHEDULED]: "Scheduled",
26
+ [CAMPAIGN_STATUS.RUNNING]: "Running",
27
+ [CAMPAIGN_STATUS.COMPLETED]: "Completed",
28
+ [CAMPAIGN_STATUS.FAILED]: "Failed",
29
+ [CAMPAIGN_STATUS.PAUSED]: "Paused",
30
+ };
31
+ return map[status] || status;
32
+ },
33
+ },
34
+ {
35
+ componentType: COMPONENT_TYPE.TEXT,
36
+ key: "scheduledAt",
37
+ textFormatter: (val) => {
38
+ if (!val)
39
+ return "-";
40
+ return formatDate(String(val), DATE_FORMATS.YYYY_MM_DD);
41
+ },
42
+ },
43
+ {
44
+ componentType: COMPONENT_TYPE.TEXT,
45
+ key: "allStudents",
46
+ textFormatter: (val) => val ? "All Students" : "Selected",
47
+ },
48
+ { componentType: COMPONENT_TYPE.TEXT, key: "successCount" },
49
+ { componentType: COMPONENT_TYPE.ACTIONS },
50
+ ];
51
+ const createComponentInstances = () => ({
52
+ filter: _jsx(PushCampaignFilter, {}),
53
+ form: _jsx(PushCampaignForm, {}),
54
+ view: _jsx(PushCampaignView, {}),
55
+ moreActions: _jsx(_Fragment, {}),
56
+ });
57
+ const createPushCampaignConfig = ({ dispatch, drawerButtonCancel, drawerButtonSave, drawerFilterDescription, drawerFilterTitle, drawerFormDescription, drawerFormTitle, drawerMoreActionsDescription, drawerMoreActionsTitle, drawerViewDescription, drawerViewTitle, tableColumnHeaderActions, tableColumnHeaderAllStudents, tableColumnHeaderId, tableColumnHeaderName, tableColumnHeaderScheduledAt, tableColumnHeaderStatus, tableColumnHeaderSuccessCount, tableColumnHeaderTitle, tableDescription, tableSearchPlaceholder, tableTitle, }) => {
58
+ const components = createComponentInstances();
59
+ return {
60
+ moduleName: "pushCampaign",
61
+ tableColumns: [
62
+ { label: tableColumnHeaderId, width: "5%" },
63
+ { label: tableColumnHeaderName, width: "20%" },
64
+ { label: tableColumnHeaderTitle, width: "20%" },
65
+ { label: tableColumnHeaderStatus, width: "10%" },
66
+ { label: tableColumnHeaderScheduledAt, width: "15%" },
67
+ { label: tableColumnHeaderAllStudents, width: "10%" },
68
+ { label: tableColumnHeaderSuccessCount, width: "10%" },
69
+ { label: tableColumnHeaderActions, width: "5%" },
70
+ ],
71
+ cancelLabel: drawerButtonCancel,
72
+ drawerFilterDescription,
73
+ drawerFilterTitle,
74
+ drawerFormDescription,
75
+ drawerFormTitle,
76
+ drawerMoreActionsDescription,
77
+ drawerMoreActionsTitle,
78
+ drawerViewDescription,
79
+ drawerViewTitle,
80
+ filterContent: components.filter,
81
+ formContent: components.form,
82
+ moreActionsContent: components.moreActions,
83
+ saveLabel: drawerButtonSave,
84
+ searchPlaceholder: tableSearchPlaceholder,
85
+ tableDescription,
86
+ tableTitle,
87
+ viewContent: components.view,
88
+ onClearFilters: () => {
89
+ dispatch({ type: PUSH_CAMPAIGN_ACTION_TYPES.RESET_FORM });
90
+ },
91
+ };
92
+ };
93
+ const GenericPushCampaignPage = createGenericModulePage();
94
+ const PushCampaignPageInner = (props) => {
95
+ const context = usePushCampaignModule();
96
+ const pushCampaignConfig = useMemo(() => createPushCampaignConfig({
97
+ dispatch: context.dispatch,
98
+ drawerButtonCancel: props.drawerButtonCancel,
99
+ drawerButtonSave: props.drawerButtonSave,
100
+ drawerFilterDescription: props.drawerFilterDescription,
101
+ drawerFilterTitle: props.drawerFilterTitle,
102
+ drawerFormDescription: props.drawerFormDescription,
103
+ drawerFormTitle: props.drawerFormTitle,
104
+ drawerMoreActionsDescription: props.drawerMoreActionsDescription,
105
+ drawerMoreActionsTitle: props.drawerMoreActionsTitle,
106
+ drawerViewDescription: props.drawerViewDescription,
107
+ drawerViewTitle: props.drawerViewTitle,
108
+ tableColumnHeaderActions: props.tableColumnHeaderActions,
109
+ tableColumnHeaderAllStudents: props.tableColumnHeaderAllStudents,
110
+ tableColumnHeaderId: props.tableColumnHeaderId,
111
+ tableColumnHeaderName: props.tableColumnHeaderName,
112
+ tableColumnHeaderScheduledAt: props.tableColumnHeaderScheduledAt,
113
+ tableColumnHeaderStatus: props.tableColumnHeaderStatus,
114
+ tableColumnHeaderSuccessCount: props.tableColumnHeaderSuccessCount,
115
+ tableColumnHeaderTitle: props.tableColumnHeaderTitle,
116
+ tableDescription: props.tableDescription,
117
+ tableSearchPlaceholder: props.tableSearchPlaceholder,
118
+ tableTitle: props.tableTitle,
119
+ }), [
120
+ context.dispatch,
121
+ props.drawerButtonCancel,
122
+ props.drawerButtonSave,
123
+ props.drawerFilterDescription,
124
+ props.drawerFilterTitle,
125
+ props.drawerFormDescription,
126
+ props.drawerFormTitle,
127
+ props.drawerMoreActionsDescription,
128
+ props.drawerMoreActionsTitle,
129
+ props.drawerViewDescription,
130
+ props.drawerViewTitle,
131
+ props.tableColumnHeaderActions,
132
+ props.tableColumnHeaderAllStudents,
133
+ props.tableColumnHeaderId,
134
+ props.tableColumnHeaderName,
135
+ props.tableColumnHeaderScheduledAt,
136
+ props.tableColumnHeaderStatus,
137
+ props.tableColumnHeaderSuccessCount,
138
+ props.tableColumnHeaderTitle,
139
+ props.tableDescription,
140
+ props.tableSearchPlaceholder,
141
+ props.tableTitle,
142
+ ]);
143
+ const hasPermission = resolveRbacPermissions({
144
+ userRole: props.userRole,
145
+ moduleName: "Communication",
146
+ });
147
+ if (!hasPermission) {
148
+ return _jsx(RbacNoAccess, { moduleName: "Communication" });
149
+ }
150
+ return (_jsx("div", { className: "p-4", children: _jsx(GenericPushCampaignPage, { overrideConfig: pushCampaignConfig, context: context, tableBodyCols: tableBodyCols }) }));
151
+ };
152
+ export const PushCampaignPage = (props) => (_jsx(PushCampaignProvider, { children: _jsx(PushCampaignPageInner, Object.assign({}, props)) }));
@@ -0,0 +1,11 @@
1
+ import { z } from "zod";
2
+ export declare const pushCampaignFormValidation: z.ZodObject<{
3
+ name: z.ZodString;
4
+ title: z.ZodString;
5
+ body: z.ZodString;
6
+ scheduledAt: z.ZodString;
7
+ allStudents: z.ZodOptional<z.ZodBoolean>;
8
+ enabled: z.ZodOptional<z.ZodBoolean>;
9
+ id: z.ZodOptional<z.ZodString>;
10
+ schoolId: z.ZodString;
11
+ }, z.core.$strip>;
@@ -0,0 +1,11 @@
1
+ import { z } from "zod";
2
+ export const pushCampaignFormValidation = z.object({
3
+ name: z.string().min(1, "Campaign name is required"),
4
+ title: z.string().min(1, "Notification title is required").max(100, "Title must be 100 characters or less"),
5
+ body: z.string().min(1, "Notification body is required").max(300, "Body must be 300 characters or less"),
6
+ scheduledAt: z.string().min(1, "Send time is required"),
7
+ allStudents: z.boolean().optional(),
8
+ enabled: z.boolean().optional(),
9
+ id: z.string().optional(),
10
+ schoolId: z.string(),
11
+ });
@@ -0,0 +1 @@
1
+ export declare const PushCampaignView: () => import("react").JSX.Element;
@@ -0,0 +1,26 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle, } from "@appcorp/shadcn/components/ui/card";
4
+ import { Badge } from "@appcorp/shadcn/components/ui/badge";
5
+ import { formatDate, DATE_FORMATS, } from "@react-pakistan/util-functions/general/format-date";
6
+ import { Bell, Calendar, CheckCircle2, XCircle, Clock, Users, } from "lucide-react";
7
+ import { useTranslations } from "next-intl";
8
+ import { usePushCampaignModule } from "./context";
9
+ export const PushCampaignView = () => {
10
+ const t = useTranslations("pushCampaign");
11
+ const context = usePushCampaignModule();
12
+ const { allStudents, body, enabled, failedCount, name, scheduledAt, status, successCount, title, totalCount, } = context.state;
13
+ const statusBadgeVariant = {
14
+ DRAFT: "secondary",
15
+ SCHEDULED: "outline",
16
+ RUNNING: "default",
17
+ COMPLETED: "default",
18
+ FAILED: "destructive",
19
+ PAUSED: "secondary",
20
+ };
21
+ return (_jsxs("div", { className: "space-y-6", children: [_jsxs(Card, { children: [_jsxs(CardHeader, { children: [_jsxs(CardTitle, { className: "flex items-center gap-2", children: [_jsx(Bell, { className: "h-5 w-5" }), name || t("viewUntitled")] }), _jsxs(CardDescription, { className: "flex items-center gap-2", children: [_jsx(Badge, { variant: statusBadgeVariant[status] || "secondary", children: t(`status${status}`) }), !enabled && (_jsx(Badge, { variant: "destructive", children: t("viewDisabled") }))] })] }), _jsxs(CardContent, { className: "space-y-4", children: [_jsxs("div", { children: [_jsx("h4", { className: "font-semibold", children: t("viewTitle") }), _jsx("p", { children: title })] }), _jsxs("div", { children: [_jsx("h4", { className: "font-semibold", children: t("viewBody") }), _jsx("p", { children: body })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Calendar, { className: "h-4 w-4 text-muted-foreground" }), _jsx("span", { children: scheduledAt
22
+ ? formatDate(scheduledAt, DATE_FORMATS.DAY_DD_MM_YYYY)
23
+ : t("viewNotScheduled") })] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Users, { className: "h-4 w-4 text-muted-foreground" }), _jsx("span", { children: allStudents
24
+ ? t("viewAllStudents")
25
+ : t("viewSelectedAudience") })] })] })] }), (status === "COMPLETED" || status === "RUNNING" || status === "FAILED") && (_jsxs(Card, { children: [_jsx(CardHeader, { children: _jsxs(CardTitle, { className: "flex items-center gap-2", children: [_jsx(Clock, { className: "h-5 w-5" }), t("viewDeliveryStats")] }) }), _jsx(CardContent, { children: _jsxs("div", { className: "grid grid-cols-3 gap-4 text-center", children: [_jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-2xl font-bold", children: totalCount }), _jsx("p", { className: "text-xs text-muted-foreground", children: t("viewTotal") })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-2xl font-bold text-green-600", children: successCount }), _jsxs("p", { className: "text-xs text-muted-foreground", children: [_jsx(CheckCircle2, { className: "inline h-3 w-3" }), " ", t("viewSuccess")] })] }), _jsxs("div", { className: "space-y-1", children: [_jsx("p", { className: "text-2xl font-bold text-red-600", children: failedCount }), _jsxs("p", { className: "text-xs text-muted-foreground", children: [_jsx(XCircle, { className: "inline h-3 w-3" }), " ", t("viewFailed")] })] })] }) })] }))] }));
26
+ };
package/constants.d.ts CHANGED
@@ -60,6 +60,11 @@ export declare const FEE_STRUCTURE_API_ROUTES: {
60
60
  export declare const PLAN_API_ROUTES: {
61
61
  readonly UNIT: "/api/v1/plan";
62
62
  };
63
+ export declare const PUSH_CAMPAIGN_API_ROUTES: {
64
+ readonly UNIT: "/api/v1/push-campaign";
65
+ readonly START: "/api/v1/push-campaign/start";
66
+ readonly AI_CHECK: "/api/v1/push-campaign/ai-check";
67
+ };
63
68
  export declare const RBAC_API_ROUTES: Record<string, string>;
64
69
  export declare const SCHOOL_API_ROUTES: Record<string, string>;
65
70
  export declare const SECTION_API_ROUTES: {
@@ -136,6 +141,7 @@ export declare const DASHBOARD_ROUTES: {
136
141
  USER_MANAGEMENT: string;
137
142
  USER: string;
138
143
  WHATSAPP_BROADCAST: string;
144
+ PUSH_CAMPAIGN: string;
139
145
  WORKSPACE_USER: string;
140
146
  WORKSPACE: string;
141
147
  };
package/constants.js CHANGED
@@ -65,6 +65,11 @@ export const FEE_STRUCTURE_API_ROUTES = {
65
65
  export const PLAN_API_ROUTES = {
66
66
  UNIT: "/api/v1/plan",
67
67
  };
68
+ export const PUSH_CAMPAIGN_API_ROUTES = {
69
+ UNIT: "/api/v1/push-campaign",
70
+ START: "/api/v1/push-campaign/start",
71
+ AI_CHECK: "/api/v1/push-campaign/ai-check",
72
+ };
68
73
  export const RBAC_API_ROUTES = {
69
74
  UNIT: "/api/v1/role",
70
75
  PERMISSIONS_LIST: "/api/v1/permission",
@@ -157,6 +162,7 @@ export const DASHBOARD_ROUTES = {
157
162
  USER_MANAGEMENT: "/user-management",
158
163
  USER: "/user-management/user",
159
164
  WHATSAPP_BROADCAST: "/communication/whatsapp-broadcast",
165
+ PUSH_CAMPAIGN: "/communication/push-campaign",
160
166
  WORKSPACE_USER: "/user-management/workspace-user",
161
167
  WORKSPACE: "/account/workspace",
162
168
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@appcorp/fusion-storybook",
3
- "version": "0.3.45",
3
+ "version": "0.3.46",
4
4
  "scripts": {
5
5
  "build-storybook": "storybook build",
6
6
  "build:next": "next build",