@eka-care/abdm-dashboard-stg 0.0.1
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 +73 -0
- package/eslint.config.js +23 -0
- package/index.html +27 -0
- package/package.json +46 -0
- package/postcss.config.js +6 -0
- package/public/headerImg.png +0 -0
- package/public/iphoneStep2.png +0 -0
- package/public/iphoneStep3.png +0 -0
- package/public/vite.svg +1 -0
- package/src/abdm-dashboard.tsx +18 -0
- package/src/app/store.ts +15 -0
- package/src/appointment-token-pdf/pdf-page1.tsx +324 -0
- package/src/appointment-token-pdf/pdf-page2.tsx +346 -0
- package/src/assets/react.svg +1 -0
- package/src/components/abha-metric.tsx +322 -0
- package/src/components/abha-workflows.tsx +225 -0
- package/src/components/automate-strip.tsx +29 -0
- package/src/components/cards/metric-card.tsx +75 -0
- package/src/components/cards/request-card.tsx +23 -0
- package/src/components/cards/request-cards.tsx +24 -0
- package/src/components/cards/workflow-card.tsx +55 -0
- package/src/components/custom/calendar.tsx +59 -0
- package/src/components/custom/switch.tsx +32 -0
- package/src/components/loader/abdm-dash-loader.tsx +21 -0
- package/src/components/loader/card-loader.tsx +20 -0
- package/src/components/modal/automateTaks-modal.tsx +110 -0
- package/src/components/modal/modal.tsx +67 -0
- package/src/components/modal/select-lang-modal.tsx +38 -0
- package/src/components/notification-header.tsx +11 -0
- package/src/features/api/baseApi.ts +23 -0
- package/src/features/cardApis/cardApi.ts +15 -0
- package/src/features/landingApi/landingApi.ts +20 -0
- package/src/features/slice/landingApiSlice.ts +49 -0
- package/src/features/tasksApis/taskGetApi.ts +12 -0
- package/src/features/tasksApis/taskUpdateApi.ts +15 -0
- package/src/home.tsx +132 -0
- package/src/index.css +297 -0
- package/src/main.tsx +107 -0
- package/src/tailwind-theme-config/pds2/border.ts +69 -0
- package/src/tailwind-theme-config/pds2/colors.ts +88 -0
- package/src/tailwind-theme-config/pds2/spacing.ts +1007 -0
- package/src/types/pagify-sdk.d.ts +17 -0
- package/src/utils/constants.ts +19 -0
- package/src/utils/helpers.ts +32 -0
- package/tailwind.config.ts +131 -0
- package/tsconfig.app.json +28 -0
- package/tsconfig.json +7 -0
- package/tsconfig.node.json +26 -0
- package/vite.config.ts +62 -0
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
2
|
+
import { useGetCardMutation } from "../features/cardApis/cardApi";
|
|
3
|
+
import {
|
|
4
|
+
faChartLine,
|
|
5
|
+
faCheck,
|
|
6
|
+
faClinicMedical,
|
|
7
|
+
faFileMedicalAlt,
|
|
8
|
+
faLink,
|
|
9
|
+
} from "@fortawesome/free-solid-svg-icons";
|
|
10
|
+
import MetricCard from "./cards/metric-card";
|
|
11
|
+
import { useEffect, useState } from "react";
|
|
12
|
+
import { formatDateToBackendISO, getYesterday } from "../utils/helpers";
|
|
13
|
+
import { DATA_DATE_FILTERS } from "../utils/constants";
|
|
14
|
+
import { getClinicId, getHfrId } from "../features/slice/landingApiSlice";
|
|
15
|
+
import { useSelector } from "react-redux";
|
|
16
|
+
import CustomCalendar from "./custom/calendar";
|
|
17
|
+
|
|
18
|
+
type ValuePiece = Date | null;
|
|
19
|
+
|
|
20
|
+
type Value = ValuePiece | [ValuePiece, ValuePiece];
|
|
21
|
+
|
|
22
|
+
const AbhaMetric = () => {
|
|
23
|
+
const clinicId = useSelector(getClinicId);
|
|
24
|
+
const hfrId = useSelector(getHfrId);
|
|
25
|
+
const [isStartDateOpen, setIsStartDateOpen] = useState<boolean>(false);
|
|
26
|
+
const [isEndDateOpen, setIsEndDateOpen] = useState<boolean>(false);
|
|
27
|
+
const [getCard, { data, isSuccess }] = useGetCardMutation();
|
|
28
|
+
const [metricData, setMetricData] = useState<any[]>([
|
|
29
|
+
{ title: "loader" },
|
|
30
|
+
{ title: "loader" },
|
|
31
|
+
{ title: "loader" },
|
|
32
|
+
]);
|
|
33
|
+
const [date, setDate] = useState<{
|
|
34
|
+
from: Value;
|
|
35
|
+
to: Value;
|
|
36
|
+
}>({
|
|
37
|
+
from: null,
|
|
38
|
+
to: null,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const [selectedDataFilter, setSelectedDataFilter] =
|
|
42
|
+
useState<DATA_DATE_FILTERS>(DATA_DATE_FILTERS.YESTERDAY);
|
|
43
|
+
|
|
44
|
+
const [cardApiBody, setCardApiBody] = useState<{
|
|
45
|
+
from?: string;
|
|
46
|
+
to?: string;
|
|
47
|
+
}>({
|
|
48
|
+
from: getYesterday().start,
|
|
49
|
+
to: getYesterday().end,
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const today = new Date();
|
|
53
|
+
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
getCard({
|
|
56
|
+
clinicId: clinicId ?? "",
|
|
57
|
+
body: {
|
|
58
|
+
start_date: cardApiBody?.from,
|
|
59
|
+
end_date: cardApiBody?.to,
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
}, [cardApiBody]);
|
|
63
|
+
|
|
64
|
+
useEffect(() => {
|
|
65
|
+
if (isSuccess && data) {
|
|
66
|
+
setMetricData(data);
|
|
67
|
+
}
|
|
68
|
+
}, [isSuccess, data]);
|
|
69
|
+
|
|
70
|
+
const handleDateChange = (key: "from" | "to", value: Value) => {
|
|
71
|
+
if (Array.isArray(value)) {
|
|
72
|
+
console.warn("Range mode not supported here", value);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
setDate({
|
|
77
|
+
...date,
|
|
78
|
+
[key]: value,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
setCardApiBody((prev) => ({
|
|
82
|
+
...prev,
|
|
83
|
+
[key]: value ? value.toISOString() : "",
|
|
84
|
+
}));
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const handleDateFilterChange = (dateFilter: DATA_DATE_FILTERS): void => {
|
|
88
|
+
if (dateFilter === DATA_DATE_FILTERS.YESTERDAY) {
|
|
89
|
+
setCardApiBody({
|
|
90
|
+
from: getYesterday().start,
|
|
91
|
+
to: getYesterday().end,
|
|
92
|
+
});
|
|
93
|
+
setSelectedDataFilter(dateFilter);
|
|
94
|
+
return;
|
|
95
|
+
} else if (dateFilter === DATA_DATE_FILTERS.MONTHLY) {
|
|
96
|
+
const startOfMonth = new Date(today.getFullYear(), today.getMonth(), 1);
|
|
97
|
+
|
|
98
|
+
const endDate = today;
|
|
99
|
+
|
|
100
|
+
const from = formatDateToBackendISO(
|
|
101
|
+
startOfMonth.toISOString().split("T")[0]
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const to = formatDateToBackendISO(endDate.toISOString().split("T")[0]);
|
|
105
|
+
|
|
106
|
+
setCardApiBody({ from, to });
|
|
107
|
+
setSelectedDataFilter(dateFilter);
|
|
108
|
+
return;
|
|
109
|
+
} else if (dateFilter === DATA_DATE_FILTERS.CUSTOM) {
|
|
110
|
+
setIsStartDateOpen(true);
|
|
111
|
+
|
|
112
|
+
if (Array.isArray(date?.from) || Array.isArray(date?.to)) {
|
|
113
|
+
console.warn("Range mode not supported here");
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
setCardApiBody({
|
|
118
|
+
from: date?.from ? date?.from?.toISOString() : "",
|
|
119
|
+
to: date?.to ? date?.to?.toISOString() : "",
|
|
120
|
+
});
|
|
121
|
+
setSelectedDataFilter(dateFilter);
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
return (
|
|
126
|
+
<div className="abhaDash-bg-gradient-to-r abhaDash-from-[#DBE5FF] abhaDash-to-[#8EAEFF] abhaDash-p-25 ">
|
|
127
|
+
<div className="abhaDash-flex abhaDash-gap-20 max-md:abhaDash-justify-between">
|
|
128
|
+
<div className="AbhaTitlesSubheadline max-md:AbhaTitle2Subheadline">ABHA Metrics</div>
|
|
129
|
+
{hfrId && (
|
|
130
|
+
<div
|
|
131
|
+
className="AbhaBody2Regular
|
|
132
|
+
abhaDash-gap-5 abhaDash-py-5
|
|
133
|
+
abhaDash-w-fit abhaDash-px-20
|
|
134
|
+
abhaDash-flex abhaDash-justify-center
|
|
135
|
+
abhaDash-items-center
|
|
136
|
+
abhaDash-text-text-primary-dark
|
|
137
|
+
abhaDash-bg-bg-primary-container
|
|
138
|
+
abhaDash-border
|
|
139
|
+
abhaDash-border-bg-white
|
|
140
|
+
abhaDash-rounded-20
|
|
141
|
+
|
|
142
|
+
max-md:abhaDash-px-10"
|
|
143
|
+
>
|
|
144
|
+
<FontAwesomeIcon icon={faClinicMedical} />
|
|
145
|
+
HFR ID: {hfrId}
|
|
146
|
+
</div>
|
|
147
|
+
)}
|
|
148
|
+
</div>
|
|
149
|
+
<div className="AbhaBody2Regular abhaDash-text-text-neutral-800-dark abhaDash-py-10">
|
|
150
|
+
Data for today and this month (last synced 1 day ago)
|
|
151
|
+
</div>
|
|
152
|
+
<div className="abhaDash-flex abhaDash-flex-wrap abhaDash-gap-8 ">
|
|
153
|
+
<div
|
|
154
|
+
onClick={
|
|
155
|
+
isSuccess
|
|
156
|
+
? () => handleDateFilterChange(DATA_DATE_FILTERS.YESTERDAY)
|
|
157
|
+
: undefined
|
|
158
|
+
}
|
|
159
|
+
className={`
|
|
160
|
+
${isSuccess ? "abhaDash-cursor-pointer" : "abhaDash-cursor-not-allowed"}
|
|
161
|
+
${
|
|
162
|
+
selectedDataFilter === DATA_DATE_FILTERS.YESTERDAY
|
|
163
|
+
? "abhaDash-border-text-primary abhaDash-text-text-primary"
|
|
164
|
+
: "abhaDash-border-border-neutral-300-strokedark"
|
|
165
|
+
} abhaDash-flex abhaDash-items-center abhaDash-gap-5 abhaDash-py-10 abhaDash-px-12 abhaDash-bg-bg-white abhaDash-border-1 abhaDash-rounded-10`}
|
|
166
|
+
>
|
|
167
|
+
{selectedDataFilter === DATA_DATE_FILTERS.YESTERDAY && (
|
|
168
|
+
<FontAwesomeIcon icon={faCheck} />
|
|
169
|
+
)}
|
|
170
|
+
Yesterday
|
|
171
|
+
</div>
|
|
172
|
+
<div
|
|
173
|
+
onClick={
|
|
174
|
+
isSuccess
|
|
175
|
+
? () => handleDateFilterChange(DATA_DATE_FILTERS.MONTHLY)
|
|
176
|
+
: undefined
|
|
177
|
+
}
|
|
178
|
+
className={`
|
|
179
|
+
${isSuccess ? "abhaDash-cursor-pointer" : "abhaDash-cursor-not-allowed"}
|
|
180
|
+
${
|
|
181
|
+
selectedDataFilter === DATA_DATE_FILTERS.MONTHLY
|
|
182
|
+
? "abhaDash-border-text-primary abhaDash-text-text-primary"
|
|
183
|
+
: "abhaDash-border-border-neutral-300-strokedark"
|
|
184
|
+
} abhaDash-flex abhaDash-items-center abhaDash-gap-5 abhaDash-py-10 abhaDash-px-12 abhaDash-bg-bg-white abhaDash-border-1 abhaDash-rounded-10`}
|
|
185
|
+
>
|
|
186
|
+
{selectedDataFilter === DATA_DATE_FILTERS.MONTHLY && (
|
|
187
|
+
<FontAwesomeIcon icon={faCheck} />
|
|
188
|
+
)}
|
|
189
|
+
Monthly
|
|
190
|
+
</div>
|
|
191
|
+
<div
|
|
192
|
+
className={`abhaDash-flex ${isSuccess ? "abhaDash-cursor-pointer" : "abhaDash-cursor-not-allowed"}`}
|
|
193
|
+
>
|
|
194
|
+
<div
|
|
195
|
+
onClick={
|
|
196
|
+
isSuccess
|
|
197
|
+
? () => handleDateFilterChange(DATA_DATE_FILTERS.CUSTOM)
|
|
198
|
+
: undefined
|
|
199
|
+
}
|
|
200
|
+
className={`${
|
|
201
|
+
selectedDataFilter === DATA_DATE_FILTERS.CUSTOM
|
|
202
|
+
? "abhaDash-border-text-primary abhaDash-text-text-primary"
|
|
203
|
+
: "abhaDash-border-border-neutral-300-strokedark"
|
|
204
|
+
} abhaDash-flex abhaDash-items-center abhaDash-gap-5 abhaDash-py-10 abhaDash-px-12 abhaDash-bg-bg-white abhaDash-border-y-1 abhaDash-border-l-1 abhaDash-rounded-l-10`}
|
|
205
|
+
>
|
|
206
|
+
{selectedDataFilter === DATA_DATE_FILTERS.CUSTOM && (
|
|
207
|
+
<FontAwesomeIcon icon={faCheck} />
|
|
208
|
+
)}
|
|
209
|
+
Custom
|
|
210
|
+
</div>
|
|
211
|
+
|
|
212
|
+
<div
|
|
213
|
+
className={`${
|
|
214
|
+
selectedDataFilter === DATA_DATE_FILTERS.CUSTOM
|
|
215
|
+
? "abhaDash-border-text-primary"
|
|
216
|
+
: "abhaDash-border-border-neutral-300-strokedark abhaDash-text-border-neutral-300-strokedark abhaDash-cursor-not-allowed"
|
|
217
|
+
} abhaDash-flex abhaDash-items-center abhaDash-gap-5 abhaDash-py-10 abhaDash-px-12 abhaDash-bg-bg-white abhaDash-border-y-1 abhaDash-border-l-1 text-center`}
|
|
218
|
+
>
|
|
219
|
+
<CustomCalendar
|
|
220
|
+
value={date.from}
|
|
221
|
+
onChange={(val) => handleDateChange("from", val)}
|
|
222
|
+
placeholder="Start Date"
|
|
223
|
+
disabled={selectedDataFilter !== DATA_DATE_FILTERS.CUSTOM}
|
|
224
|
+
minDate={undefined}
|
|
225
|
+
isOpen={isStartDateOpen}
|
|
226
|
+
onCalendarClose={() => {
|
|
227
|
+
setIsEndDateOpen(true);
|
|
228
|
+
}}
|
|
229
|
+
/>
|
|
230
|
+
</div>
|
|
231
|
+
<div
|
|
232
|
+
className={`${
|
|
233
|
+
selectedDataFilter === DATA_DATE_FILTERS.CUSTOM
|
|
234
|
+
? "abhaDash-border-text-primary"
|
|
235
|
+
: "abhaDash-border-border-neutral-300-strokedark abhaDash-text-border-neutral-300-strokedark abhaDash-cursor-not-allowed"
|
|
236
|
+
} abhaDash-py-10 abhaDash-px-12 abhaDash-bg-bg-white abhaDash-border-y-1`}
|
|
237
|
+
>
|
|
238
|
+
-
|
|
239
|
+
</div>
|
|
240
|
+
<div
|
|
241
|
+
className={`${
|
|
242
|
+
selectedDataFilter === DATA_DATE_FILTERS.CUSTOM
|
|
243
|
+
? "abhaDash-border-text-primary"
|
|
244
|
+
: "abhaDash-border-border-neutral-300-strokedark abhaDash-text-border-neutral-300-strokedark abhaDash-cursor-not-allowed"
|
|
245
|
+
} abhaDash-flex abhaDash-items-center abhaDash-gap-5 abhaDash-py-10 abhaDash-px-12 abhaDash-bg-bg-white abhaDash-border-y-1 abhaDash-border-r-1 abhaDash-rounded-r-10 text-center`}
|
|
246
|
+
>
|
|
247
|
+
<CustomCalendar
|
|
248
|
+
value={date.to}
|
|
249
|
+
onChange={(val) => handleDateChange("to", val)}
|
|
250
|
+
placeholder="End Date"
|
|
251
|
+
disabled={selectedDataFilter !== DATA_DATE_FILTERS.CUSTOM}
|
|
252
|
+
isOpen={isEndDateOpen}
|
|
253
|
+
minDate={
|
|
254
|
+
date.from instanceof Date
|
|
255
|
+
? new Date(
|
|
256
|
+
date.from.getFullYear(),
|
|
257
|
+
date.from.getMonth(),
|
|
258
|
+
date.from.getDate() + 1
|
|
259
|
+
)
|
|
260
|
+
: undefined
|
|
261
|
+
}
|
|
262
|
+
onCalendarClose={() => {
|
|
263
|
+
setIsEndDateOpen(false);
|
|
264
|
+
setIsStartDateOpen(false);
|
|
265
|
+
}}
|
|
266
|
+
/>
|
|
267
|
+
</div>
|
|
268
|
+
</div>
|
|
269
|
+
</div>
|
|
270
|
+
<div className="abhaDash-flex abhaDash-flex-wrap abhaDash-gap-20 abhaDash-h-full abhaDash-pt-20 ">
|
|
271
|
+
{metricData?.map((val, idx) => {
|
|
272
|
+
return (
|
|
273
|
+
<MetricCard
|
|
274
|
+
isDataLoaded={isSuccess}
|
|
275
|
+
key={val?.id ?? idx}
|
|
276
|
+
title={val?.title}
|
|
277
|
+
successText={
|
|
278
|
+
val?.title?.includes("Consent") ? "Successful" : "KYC Linked"
|
|
279
|
+
}
|
|
280
|
+
failedText={
|
|
281
|
+
val?.title?.includes("Consent") ? "Unsuccessful" : "Non KYC"
|
|
282
|
+
}
|
|
283
|
+
success={
|
|
284
|
+
val?.id?.includes("consent")
|
|
285
|
+
? val?.data?.success
|
|
286
|
+
: val?.data?.kyc
|
|
287
|
+
}
|
|
288
|
+
failed={
|
|
289
|
+
val?.id?.includes("consent")
|
|
290
|
+
? val?.data?.failed
|
|
291
|
+
: val?.data?.non_kyc
|
|
292
|
+
}
|
|
293
|
+
total={val?.data?.total}
|
|
294
|
+
cardIcon={
|
|
295
|
+
val?.id?.includes("abha")
|
|
296
|
+
? faChartLine
|
|
297
|
+
: val?.id?.includes("records")
|
|
298
|
+
? faLink
|
|
299
|
+
: faFileMedicalAlt
|
|
300
|
+
}
|
|
301
|
+
/>
|
|
302
|
+
);
|
|
303
|
+
})}
|
|
304
|
+
{/* <div className="abhaDash-w-260 abhaDash-h-[55%] abhaDash-border-1 abhaDash-rounded-20 abhaDash-border-bg-primary-light abhaDash-bg-gradient-to-r abhaDash-from-[#95E9C1] abhaDash-to-[#D8FF71] abhaDash-p-20">
|
|
305
|
+
<div className="AbhaTitleHeadline abhaDash-text-text-primary-dark">
|
|
306
|
+
₹400
|
|
307
|
+
</div>
|
|
308
|
+
<div className="AbhaTitle2Headline">DHIS Earnings</div>
|
|
309
|
+
<div className="abhaDash-border abhaDash-border-border-green-light abhaDash-my-10"></div>
|
|
310
|
+
<div className="AbhaTitle2Headline abhaDash-text-text-primary abhaDash-py-6">
|
|
311
|
+
See Calculation
|
|
312
|
+
</div>
|
|
313
|
+
<div className="AbhaBody3Regular abhaDash-text-text-neutral-800-dark">
|
|
314
|
+
Last synced 1 day ago*
|
|
315
|
+
</div>
|
|
316
|
+
</div> */}
|
|
317
|
+
</div>
|
|
318
|
+
</div>
|
|
319
|
+
);
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
export default AbhaMetric;
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import {
|
|
2
|
+
faDownload,
|
|
3
|
+
faLink,
|
|
4
|
+
faUserPlus,
|
|
5
|
+
} from "@fortawesome/free-solid-svg-icons";
|
|
6
|
+
import WorkFlowCard from "./cards/workflow-card";
|
|
7
|
+
import pagify from "@eka-care/pagify-sdk";
|
|
8
|
+
import { PdfPage1 } from "../appointment-token-pdf/pdf-page1";
|
|
9
|
+
import { renderToStaticMarkup } from "react-dom/server";
|
|
10
|
+
import { PdfPage2 } from "../appointment-token-pdf/pdf-page2";
|
|
11
|
+
import { useSelector } from "react-redux";
|
|
12
|
+
import { getQrURl, getClinicName } from "../features/slice/landingApiSlice";
|
|
13
|
+
import QRCode from "react-qr-code";
|
|
14
|
+
|
|
15
|
+
const AbhaWorkFlows = ({
|
|
16
|
+
setShowAbhaSDK,
|
|
17
|
+
setShowWorkflowIframe,
|
|
18
|
+
}: {
|
|
19
|
+
setShowAbhaSDK: (show: boolean) => void;
|
|
20
|
+
setShowWorkflowIframe: (show: boolean) => void;
|
|
21
|
+
}) => {
|
|
22
|
+
const qrUrl = useSelector(getQrURl);
|
|
23
|
+
const clinicName = useSelector(getClinicName);
|
|
24
|
+
|
|
25
|
+
const handlePdfGenerate = async () => {
|
|
26
|
+
const innerHtml = renderToStaticMarkup(
|
|
27
|
+
<PdfPage1
|
|
28
|
+
qrUrl={qrUrl ?? "test"}
|
|
29
|
+
clinicName={clinicName ?? "Test Clinic"}
|
|
30
|
+
/>
|
|
31
|
+
);
|
|
32
|
+
const innerHtml1 = renderToStaticMarkup(<PdfPage2 />);
|
|
33
|
+
|
|
34
|
+
const bodyHtml =
|
|
35
|
+
"<!doctype html>" +
|
|
36
|
+
`<div id="pagify-root" class="page-break" style="transform:rotate(90deg);">` +
|
|
37
|
+
innerHtml +
|
|
38
|
+
`</div>` +
|
|
39
|
+
`<div class="page-break-avoid" style="transform:rotate(90deg);">` +
|
|
40
|
+
innerHtml1 +
|
|
41
|
+
`</div>`;
|
|
42
|
+
|
|
43
|
+
await pagify.render({
|
|
44
|
+
head_html: `
|
|
45
|
+
<style>
|
|
46
|
+
.page-break-avoid { page-break-inside: avoid; }
|
|
47
|
+
.page-break {
|
|
48
|
+
page-break-after: always;
|
|
49
|
+
}
|
|
50
|
+
</style>
|
|
51
|
+
`,
|
|
52
|
+
body_html: bodyHtml,
|
|
53
|
+
page_size: "A4",
|
|
54
|
+
onPdfReady: (blobUrl: string) => {
|
|
55
|
+
const a = document.createElement("a");
|
|
56
|
+
a.href = blobUrl;
|
|
57
|
+
a.target = "_blank";
|
|
58
|
+
document.body.appendChild(a);
|
|
59
|
+
a.click();
|
|
60
|
+
a.remove();
|
|
61
|
+
},
|
|
62
|
+
onPdfError: (error: any) => {
|
|
63
|
+
console.error("PDF generation failed:", error);
|
|
64
|
+
},
|
|
65
|
+
} as any);
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
function waitForElement(
|
|
69
|
+
id: string,
|
|
70
|
+
callback: (element: HTMLElement) => void
|
|
71
|
+
): void {
|
|
72
|
+
const interval = setInterval(() => {
|
|
73
|
+
const el = document.getElementById(id);
|
|
74
|
+
if (el) {
|
|
75
|
+
clearInterval(interval);
|
|
76
|
+
callback(el);
|
|
77
|
+
}
|
|
78
|
+
}, 50);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const handleAbhaSDKMount = () => {
|
|
82
|
+
setShowAbhaSDK(true);
|
|
83
|
+
|
|
84
|
+
if (typeof window === "undefined") return;
|
|
85
|
+
|
|
86
|
+
waitForElement("abha-container", () => {
|
|
87
|
+
console.log("🎉 abha-container found!");
|
|
88
|
+
|
|
89
|
+
if (typeof window.initAbhaApp !== "function") {
|
|
90
|
+
console.error("❌ initAbhaApp is not available on window.");
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
window.initAbhaApp({
|
|
95
|
+
clientId: "doc-web",
|
|
96
|
+
containerId: "abha-container",
|
|
97
|
+
method: "create_abha_with_mobile",
|
|
98
|
+
data: {},
|
|
99
|
+
|
|
100
|
+
onSuccess: ({ response }) => {
|
|
101
|
+
console.log("✅ ABHA Success:", response);
|
|
102
|
+
const t = new window.Bridge();
|
|
103
|
+
t.refreshPatientDirectory();
|
|
104
|
+
setShowAbhaSDK(false);
|
|
105
|
+
},
|
|
106
|
+
|
|
107
|
+
onError: ({ error, response }) => {
|
|
108
|
+
console.error("❌ ABHA Error:", error || response);
|
|
109
|
+
setShowAbhaSDK(false);
|
|
110
|
+
},
|
|
111
|
+
|
|
112
|
+
onAbhaClose: () => {
|
|
113
|
+
console.log("❌ ABHA Close");
|
|
114
|
+
const t = new window.Bridge();
|
|
115
|
+
t.refreshPatientDirectory();
|
|
116
|
+
setShowAbhaSDK(false);
|
|
117
|
+
},
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const handleIframeMount = (type: string) => {
|
|
123
|
+
setShowWorkflowIframe(true);
|
|
124
|
+
const iframeUrl =
|
|
125
|
+
type === "upload"
|
|
126
|
+
? "https://demo.arcade.software/R8kEyxUclnWTItas93qN?embed&embed_mobile=tab&embed_desktop=inline&show_copy_link=true"
|
|
127
|
+
: "https://demo.arcade.software/Bx1vEspdLmt5omIcks6H?embed&embed_mobile=tab&embed_desktop=inline&show_copy_link=true";
|
|
128
|
+
waitForElement("iframe-container", () => {
|
|
129
|
+
const container = document.getElementById("iframe-container");
|
|
130
|
+
if (!container) return;
|
|
131
|
+
|
|
132
|
+
container.innerHTML = "";
|
|
133
|
+
const iframe = document.createElement("iframe");
|
|
134
|
+
iframe.src = iframeUrl;
|
|
135
|
+
iframe.title = "Upload and Organize Patient Lab Reports";
|
|
136
|
+
iframe.frameBorder = "0";
|
|
137
|
+
iframe.loading = "lazy";
|
|
138
|
+
iframe.allowFullscreen = true;
|
|
139
|
+
iframe.allow = "clipboard-write";
|
|
140
|
+
iframe.className = "abhaDash-h-full abhaDash-w-full";
|
|
141
|
+
iframe.style.colorScheme = "light";
|
|
142
|
+
|
|
143
|
+
container.appendChild(iframe);
|
|
144
|
+
});
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
return (
|
|
148
|
+
<div className="abhaDash-p-25 abhaDash-h-[25%] ">
|
|
149
|
+
<div className="AbhaTitlesSubheadline">ABHA Workflows</div>
|
|
150
|
+
|
|
151
|
+
<div className="AbhaBody2Regular abhaDash-text-text-neutral-800-dark abhaDash-py-10">
|
|
152
|
+
Direct access to ABDM functions
|
|
153
|
+
</div>
|
|
154
|
+
|
|
155
|
+
<div className="abhaDash-flex abhaDash-flex-wrap abhaDash-gap-20 abhaDash-pt-20 abhaDash-pb-70 abhaDash-gap-y-20">
|
|
156
|
+
<WorkFlowCard
|
|
157
|
+
bodyColor="abhaDash-bg-bg-primary-light"
|
|
158
|
+
bodyText="Generate ABHA for new patients"
|
|
159
|
+
icon={faUserPlus}
|
|
160
|
+
iconBgGradColorFrom="abhaDash-from-[#2B7FFF]"
|
|
161
|
+
iconBgGradColorTo="abhaDash-to-[#155DFC]"
|
|
162
|
+
btnText="Create ABHA"
|
|
163
|
+
disabled={false}
|
|
164
|
+
cta={handleAbhaSDKMount}
|
|
165
|
+
mobileStyling={"max-md:abhaDash-w-169"}
|
|
166
|
+
/>
|
|
167
|
+
|
|
168
|
+
<WorkFlowCard
|
|
169
|
+
bodyColor="abhaDash-bg-bg-yellow-light"
|
|
170
|
+
bodyText="Retrieve patient data from ABDM"
|
|
171
|
+
icon={faDownload}
|
|
172
|
+
iconBgGradColorFrom="abhaDash-from-[#FE9A00]"
|
|
173
|
+
iconBgGradColorTo="abhaDash-to-[#FF6900]"
|
|
174
|
+
btnText="Fetch Records"
|
|
175
|
+
disabled={false}
|
|
176
|
+
cta={() => handleIframeMount("fetch")}
|
|
177
|
+
mobileStyling={"max-md:abhaDash-w-169"}
|
|
178
|
+
/>
|
|
179
|
+
<WorkFlowCard
|
|
180
|
+
bodyColor="abhaDash-bg-bg-green-light"
|
|
181
|
+
bodyText="Connect patient records to ABHA"
|
|
182
|
+
icon={faLink}
|
|
183
|
+
iconBgGradColorFrom="abhaDash-from-[#00BC7D]"
|
|
184
|
+
iconBgGradColorTo="abhaDash-to-[#009966]"
|
|
185
|
+
btnText="Upload & Link Records"
|
|
186
|
+
disabled={false}
|
|
187
|
+
cta={() => handleIframeMount("upload")}
|
|
188
|
+
mobileStyling={"max-md:abhaDash-w-360 max-md:abhaDash-flex max-md:abhaDash-gap-10 max-md:abhaDash-items-center"}
|
|
189
|
+
/>
|
|
190
|
+
|
|
191
|
+
<div className="abhaDash-h-full abhaDash-w-380 abhaDash-pb-20">
|
|
192
|
+
<div className="abhaDash-w-full abhaDash-from-[#205CFF] abhaDash-to-[#AE71D2] abhaDash-bg-gradient-to-r abhaDash-border-1 abhaDash-rounded-20 abhaDash-border-bg-neutral-100-bg-dark abhaDash-p-20 ">
|
|
193
|
+
<div className="abhaDash-flex abhaDash-h-135 abhaDash-gap-20 abhaDash-text-text-white ">
|
|
194
|
+
<div className="abhaDash-h-full">
|
|
195
|
+
<QRCode
|
|
196
|
+
className="abhaDash-h-full abhaDash-w-full abhaDash-border abhaDash-border-bg-04 abhaDash-p-10 abhaDash-rounded-10"
|
|
197
|
+
value={qrUrl ?? ""}
|
|
198
|
+
/>
|
|
199
|
+
</div>
|
|
200
|
+
|
|
201
|
+
<div className="abhaDash-flex-col abhaDash-flex abhaDash-justify-center">
|
|
202
|
+
<div className="AbhaTitle2Headline abhaDash-mb-10">
|
|
203
|
+
Instant Appointment for Patients
|
|
204
|
+
</div>
|
|
205
|
+
<div className="AbhaBody3Regular abhaDash-mb-10">
|
|
206
|
+
Patients can generate ABHA and book appointments using this QR
|
|
207
|
+
Code.
|
|
208
|
+
</div>
|
|
209
|
+
<div
|
|
210
|
+
className="AbhaTitle3Headline abhaDash-py-5 abhaDash-w-fit abhaDash-px-20 abhaDash-flex abhaDash-justify-center abhaDash-text-text-primary abhaDash-bg-bg-white abhaDash-rounded-20 abhaDash-cursor-pointer"
|
|
211
|
+
onClick={handlePdfGenerate}
|
|
212
|
+
>
|
|
213
|
+
{/* Download in your Language adding soon */}
|
|
214
|
+
Download and Share
|
|
215
|
+
</div>
|
|
216
|
+
</div>
|
|
217
|
+
</div>
|
|
218
|
+
</div>
|
|
219
|
+
</div>
|
|
220
|
+
</div>
|
|
221
|
+
</div>
|
|
222
|
+
);
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
export default AbhaWorkFlows;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const AutomateStrip = ({
|
|
2
|
+
setShowAutomateModal,
|
|
3
|
+
}: {
|
|
4
|
+
setShowAutomateModal: (show: boolean) => void;
|
|
5
|
+
}) => {
|
|
6
|
+
return (
|
|
7
|
+
<div className="abhaDash-px-25">
|
|
8
|
+
<div className="max-md:abhaDash-flex-col max-md:abhaDash-py-14 max-md:abhaDash-items-start abhaDash-bg-bg-green-light abhaDash-mx-auto abhaDash-flex abhaDash-px-20 abhaDash-py-8 abhaDash-rounded-10 abhaDash-justify-between abhaDash-items-center abhaDash-mt-20">
|
|
9
|
+
<div className="AbhaBody2Regular max-md:abhaDash-hidden">
|
|
10
|
+
Maximise your earnings by sending patients KYC requests, ABHA creation
|
|
11
|
+
and consent for accessing medical history
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<div className="AbhaBody2Regular md:abhaDash-hidden">
|
|
15
|
+
Maximise your earnings by sending patients <br />
|
|
16
|
+
- KYC requests, <br />
|
|
17
|
+
- ABHA creation, and <br />- Consent for accessing medical history
|
|
18
|
+
</div>
|
|
19
|
+
<div
|
|
20
|
+
onClick={() => setShowAutomateModal(true)}
|
|
21
|
+
className="max-md:abhaDash-w-full max-md:abhaDash-text-center max-md:abhaDash-mt-14 AbhaTitle3Headline abhaDash-px-12 abhaDash-py-10 abhaDash-rounded-8 abhaDash-bg-bg-doc abhaDash-text-text-white abhaDash-cursor-pointer"
|
|
22
|
+
>
|
|
23
|
+
Automate tasks
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
</div>
|
|
27
|
+
);
|
|
28
|
+
};
|
|
29
|
+
export default AutomateStrip;
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
|
2
|
+
import CardLoader from "../loader/card-loader";
|
|
3
|
+
import { faCircleInfo } from "@fortawesome/free-solid-svg-icons";
|
|
4
|
+
import Loader from "../loader/abdm-dash-loader";
|
|
5
|
+
|
|
6
|
+
const MetricCard = ({
|
|
7
|
+
isDataLoaded,
|
|
8
|
+
total,
|
|
9
|
+
success,
|
|
10
|
+
failed,
|
|
11
|
+
successText,
|
|
12
|
+
failedText,
|
|
13
|
+
title,
|
|
14
|
+
cardIcon,
|
|
15
|
+
}: {
|
|
16
|
+
isDataLoaded?: boolean;
|
|
17
|
+
total?: number;
|
|
18
|
+
success?: number;
|
|
19
|
+
failed?: number;
|
|
20
|
+
successText?: string;
|
|
21
|
+
failedText?: string;
|
|
22
|
+
title?: string;
|
|
23
|
+
cardIcon?: any;
|
|
24
|
+
}) => {
|
|
25
|
+
return isDataLoaded ? (
|
|
26
|
+
<>
|
|
27
|
+
<div className="abhaDash-w-260 max-md:abhaDash-w-[47%] abhaDash-border-1 abhaDash-rounded-20 abhaDash-border-bg-green-dark abhaDash-bg-bg-white abhaDash-p-20">
|
|
28
|
+
<div className="abhaDash-flex abhaDash-justify-between">
|
|
29
|
+
<div className="AbhaTitleHeadline abhaDash-text-text-primary-dark">
|
|
30
|
+
{total ?? 0}
|
|
31
|
+
</div>
|
|
32
|
+
<FontAwesomeIcon
|
|
33
|
+
className="abhaDash-text-text-primary abhaDash-w-28 abhaDash-h-28"
|
|
34
|
+
icon={cardIcon}
|
|
35
|
+
/>
|
|
36
|
+
</div>
|
|
37
|
+
<div className="AbhaTitle2Headline">{title}</div>
|
|
38
|
+
|
|
39
|
+
<CardLoader value={success ?? 0} total={total ?? 0} />
|
|
40
|
+
|
|
41
|
+
<div className="abhaDash-flex abhaDash-justify-between abhaDash-pt-5">
|
|
42
|
+
<div className="AbhaBody2Regular abhaDash-text-text-neutral-800-dark abhaDash-flex">
|
|
43
|
+
{successText}
|
|
44
|
+
<div
|
|
45
|
+
title={
|
|
46
|
+
title?.includes("Consent")
|
|
47
|
+
? "No. Of consent requests granted with atleast 1 medical record(s) successfully retrieved"
|
|
48
|
+
: title?.includes("Records")
|
|
49
|
+
? "No. Of records linked to KYC verified ABHA"
|
|
50
|
+
: "No. Of patients with KYC verified ABHA"
|
|
51
|
+
}
|
|
52
|
+
>
|
|
53
|
+
<FontAwesomeIcon
|
|
54
|
+
className="abhaDash-pl-5 abhaDash-w-14 abhaDash-h-14 abhaDash-cursor-pointer"
|
|
55
|
+
icon={faCircleInfo}
|
|
56
|
+
/>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
<div className="abhaDash-text-text-primary-dark">{success}</div>
|
|
60
|
+
</div>
|
|
61
|
+
<div className="abhaDash-flex abhaDash-justify-between">
|
|
62
|
+
<div className="AbhaBody2Regular abhaDash-text-text-neutral-800-dark">
|
|
63
|
+
{failedText}
|
|
64
|
+
</div>
|
|
65
|
+
<div className="abhaDash-text-text-red-primary">{failed}</div>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
</>
|
|
69
|
+
) : (
|
|
70
|
+
<div className="abhaDash-w-260 max-md:abhaDash-w-[47%] abhaDash-h-1/2 abhaDash-border-1 abhaDash-rounded-20 abhaDash-border-bg-green-dark abhaDash-bg-bg-white abhaDash-p-65">
|
|
71
|
+
<Loader bgColor="abhaDash-bg-bg-white" />
|
|
72
|
+
</div>
|
|
73
|
+
);
|
|
74
|
+
};
|
|
75
|
+
export default MetricCard;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const RequestCard = ({
|
|
2
|
+
bodyText,
|
|
3
|
+
btnText,
|
|
4
|
+
bodyColor,
|
|
5
|
+
}: {
|
|
6
|
+
bodyText: string;
|
|
7
|
+
btnText: string;
|
|
8
|
+
bodyColor: string;
|
|
9
|
+
}) => {
|
|
10
|
+
return (
|
|
11
|
+
<div
|
|
12
|
+
className={`${bodyColor} abhaDash-gap-10 abhaDash-text-neutral-1000-black abhaDash-flex abhaDash-items-center abhaDash-p-20 abhaDash-m-5 abhaDash-rounded-20 abhaDash-w-450`}
|
|
13
|
+
>
|
|
14
|
+
<div>
|
|
15
|
+
{bodyText}
|
|
16
|
+
</div>
|
|
17
|
+
<div className="AbhaTitle3Headline abhaDash-flex abhaDash-justify-center abhaDash-w-130 abhaDash-text-text-white abhaDash-bg-bg-doc abhaDash-py-12 abhaDash-px-10 abhaDash-rounded-8">
|
|
18
|
+
{btnText}
|
|
19
|
+
</div>
|
|
20
|
+
</div>
|
|
21
|
+
);
|
|
22
|
+
};
|
|
23
|
+
export default RequestCard;
|