Skip to content

Commit 698d8b9

Browse files
committed
Implement Analytics by user data
1 parent c4a3e53 commit 698d8b9

File tree

5 files changed

+297
-58
lines changed

5 files changed

+297
-58
lines changed

Track 4_ReactJS_Web Development/Project/Frontend/hrc-dashboard/src/components/navigation/AnalyticsButton.jsx

+11-55
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,32 @@
11
import * as Mantine from '@mantine/core';
2-
import { useToggle } from '@mantine/hooks';
3-
import { showNotification } from '@mantine/notifications';
4-
import React, { useState } from 'react';
5-
import { Check, DeviceDesktopAnalytics, X } from 'tabler-icons-react';
6-
import prepareBarChart from '../../utils/analytics/prepareBarChart';
7-
import preparePieChart from '../../utils/analytics/preparePieChart';
8-
import getAnalyticsData from '../../utils/api/getAnalyticsData';
9-
import BarChart from '../analytics/BarChart';
10-
import PieChart from '../analytics/PieChart';
2+
import React, { useState, useEffect } from 'react';
3+
import { DeviceDesktopAnalytics } from 'tabler-icons-react';
4+
import CustomDrawer from './CustomDrawer';
5+
import AnalyticsForm from './Forms/AnalyticsForm';
116

127
function AnalyticsButton() {
138
const [disabled, setDisabled] = useState(false);
14-
const [modalOpened, setModalOpened] = useState(false);
15-
const [pieChartData, setPieChartData] = useState([{ id: '', label: 'null', value: 0 }]);
16-
const [barChartData, setBarChartData] = useState([{ id: '', label: 'null', value: 0 }]);
17-
const [chartToggle, setChartToggle] = useToggle('pie', ['pie', 'bar']);
9+
const [opened, setOpened] = useState(false);
10+
11+
useEffect(() => (!opened ? setDisabled(false) : setDisabled(true)), [opened]);
1812

1913
return (
2014
<>
15+
<CustomDrawer opened={opened} setOpened={setOpened} title="Analytics - Drawer">
16+
<AnalyticsForm setOpened={setOpened} setAnalyticsButtonDisabled={setDisabled} />
17+
</CustomDrawer>
2118
<Mantine.Button
2219
className={`w-auto bg-orange-400 hover:bg-orange-500 hover:cursor-pointer transition ease-in-out duration-75 ${
2320
disabled && 'blur-sm'
2421
}`}
2522
leftIcon={<DeviceDesktopAnalytics />}
2623
disabled={disabled}
2724
onClick={async () => {
28-
setDisabled(true);
29-
const analyticsData = await getAnalyticsData();
30-
setDisabled(false);
31-
if (analyticsData.length > 0) {
32-
setPieChartData(preparePieChart({ data: analyticsData }));
33-
setBarChartData(prepareBarChart({ data: analyticsData }));
34-
setModalOpened(true); // Open the modal toggling the state of it.
35-
showNotification({
36-
title: 'Alert!',
37-
message: `The analytics data are ready!`,
38-
color: 'teal',
39-
autoClose: 10000,
40-
disallowClose: false,
41-
icon: <Check size={18} />,
42-
});
43-
} else {
44-
showNotification({
45-
title: 'Alert!',
46-
message: 'The server returned error while predicting.',
47-
color: 'red',
48-
disallowClose: false,
49-
icon: <X size={18} />,
50-
});
51-
}
25+
setOpened(true);
5226
}}
5327
>
5428
Analytics
5529
</Mantine.Button>
56-
<Mantine.Modal
57-
opened={modalOpened}
58-
onClose={() => setModalOpened(false)}
59-
title={<Mantine.Title order={2}>Analytics View</Mantine.Title>}
60-
size="70%"
61-
>
62-
<Mantine.Button
63-
onClick={() => setChartToggle()}
64-
color="blue"
65-
className=" justify-center items-center mb-8 w-1/2 text-center bg-orange-400 hover:bg-orange-300"
66-
>
67-
{chartToggle.toUpperCase()}
68-
</Mantine.Button>
69-
<Mantine.Paper className="h-96 bg-lime-200">
70-
{chartToggle === 'pie' && <PieChart data={pieChartData} />}
71-
{chartToggle === 'bar' && <BarChart data={barChartData} />}
72-
</Mantine.Paper>
73-
</Mantine.Modal>
7430
</>
7531
);
7632
}

Track 4_ReactJS_Web Development/Project/Frontend/hrc-dashboard/src/components/navigation/Forms/AddForm.jsx

+2
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ export default function AddForm({ setOpened }) {
159159
{...field}
160160
{...form.getInputProps(field.htmlFor)}
161161
allowLevelChange
162+
allowFreeInput
163+
dateParser={(dateString) => new Date(Date.parse(dateString))}
162164
firstDayOfWeek="sunday"
163165
/>
164166
))}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
/* eslint-disable react/jsx-props-no-spreading */
2+
import * as Mantine from '@mantine/core';
3+
import { DatePicker } from '@mantine/dates';
4+
import { useForm, useToggle } from '@mantine/hooks';
5+
import { showNotification } from '@mantine/notifications';
6+
import PropTypes from 'prop-types';
7+
import React, { useState } from 'react';
8+
import { Check, Calendar, X } from 'tabler-icons-react';
9+
10+
import convertDateToDBFormat from '../../../utils/datefns/convertDate';
11+
import BarChart from '../../analytics/BarChart';
12+
import PieChart from '../../analytics/PieChart';
13+
import {
14+
defaultTableSchema,
15+
formInputFields,
16+
formDateFields,
17+
} from '../../../utils/schema/analyticsFormSchema';
18+
import prepareBarChart from '../../../utils/analytics/prepareBarChart';
19+
import preparePieChart from '../../../utils/analytics/preparePieChart';
20+
import getAnalyticsData from '../../../utils/api/getAnalyticsData';
21+
22+
function AnalyticsForm({ setOpened, setAnalyticsButtonDisabled }) {
23+
const form = useForm({
24+
initialValues: { ...defaultTableSchema },
25+
validate: {},
26+
});
27+
28+
const [modalOpened, setModalOpened] = useState(false);
29+
const [pieChartData, setPieChartData] = useState([{ id: '', label: 'null', value: 0 }]);
30+
const [barChartData, setBarChartData] = useState([{ id: '', label: 'null', value: 0 }]);
31+
const [chartToggle, setChartToggle] = useToggle('pie', ['pie', 'bar']);
32+
33+
const handleFormSubmission = async (values) => {
34+
// Loop through formInputFields
35+
formInputFields.forEach((field) => {
36+
const fieldValue = form.getInputProps(field.htmlFor)?.value || '';
37+
// If fieldValue is null or undefined, store null
38+
defaultTableSchema[field.htmlFor] = fieldValue;
39+
});
40+
41+
// Loop through formDateFields
42+
formDateFields.forEach((field) => {
43+
if (field.type === 'db_date') {
44+
defaultTableSchema[field.htmlFor] = convertDateToDBFormat(values[field.htmlFor.toString()]);
45+
}
46+
});
47+
48+
try {
49+
// Submit defaultTableSchema to the database
50+
/*
51+
Successful data submission example
52+
0: {rowsAffected: 1}
53+
1: {rows: 48583}
54+
2: {rows: 6}
55+
3: {rows: 1084}
56+
*/
57+
58+
const payload = {
59+
clear_date: [defaultTableSchema.clear_date_start, defaultTableSchema.clear_date_end],
60+
due_in_date: [defaultTableSchema.due_in_date_start, defaultTableSchema.due_in_date_end],
61+
baseline_create_date: [
62+
defaultTableSchema.baseline_create_date_start,
63+
defaultTableSchema.baseline_create_date_end,
64+
],
65+
invoice_currency: defaultTableSchema.invoice_currency,
66+
};
67+
const analyticsData = await getAnalyticsData(payload);
68+
if (analyticsData.length > 0) {
69+
setPieChartData(preparePieChart({ data: analyticsData }));
70+
setBarChartData(prepareBarChart({ data: analyticsData }));
71+
setModalOpened(true); // Open the modal toggling the state of it.
72+
73+
setAnalyticsButtonDisabled(false);
74+
showNotification({
75+
title: 'Alert!',
76+
message: `The analytics data are ready!`,
77+
color: 'teal',
78+
autoClose: 10000,
79+
disallowClose: false,
80+
icon: <Check size={18} />,
81+
});
82+
} else {
83+
setAnalyticsButtonDisabled(false);
84+
showNotification({
85+
title: 'Alert!',
86+
message: 'The server returned error.',
87+
color: 'red',
88+
disallowClose: false,
89+
icon: <X size={18} />,
90+
});
91+
}
92+
} catch (e) {
93+
console.error(e);
94+
showNotification({
95+
title: 'Alert!',
96+
message: e.message,
97+
color: 'red',
98+
disallowClose: false,
99+
icon: <X size={18} />,
100+
});
101+
}
102+
};
103+
const [shouldSubmitBeDisabled, setShouldSubmitBeDisabled] = React.useState(true);
104+
105+
return (
106+
<>
107+
<Mantine.Box sx={{ maxWidth: 300 }} mx="auto" oncl>
108+
<form onSubmit={form.onSubmit((values) => handleFormSubmission(values))}>
109+
<Mantine.Divider my="sm" variant="dashed" label="Get Insights" labelPosition="center" />
110+
111+
<Mantine.ScrollArea style={{ height: 550 }} className="px-5">
112+
{formInputFields.map((field) => {
113+
switch (field.type) {
114+
case 'number':
115+
return (
116+
<Mantine.NumberInput
117+
key={field.htmlFor}
118+
required={false}
119+
{...field}
120+
{...form.getInputProps(field.htmlFor)}
121+
radius="md"
122+
/>
123+
);
124+
default:
125+
return (
126+
<Mantine.TextInput
127+
key={field.htmlFor}
128+
required={false}
129+
{...field}
130+
{...form.getInputProps(field.htmlFor)}
131+
radius="md"
132+
/>
133+
);
134+
}
135+
})}
136+
137+
{/* Date Fields */}
138+
{formDateFields.map((field) => (
139+
<DatePicker
140+
key={field.htmlFor}
141+
placeholder="Pick date"
142+
required={false}
143+
icon={<Calendar size={16} />}
144+
{...field}
145+
{...form.getInputProps(field.htmlFor)}
146+
allowLevelChange
147+
firstDayOfWeek="sunday"
148+
allowFreeInput
149+
dateParser={(dateString) => new Date(Date.parse(dateString))}
150+
/>
151+
))}
152+
153+
<Mantine.Checkbox
154+
mt="md"
155+
label="I agree to the truthness of the above data."
156+
color="orange"
157+
key="checkConsent"
158+
htmlFor="checkConsent"
159+
onClick={() => setShouldSubmitBeDisabled(!shouldSubmitBeDisabled)}
160+
{...form.getInputProps('checkConsent', { type: 'checkbox' })}
161+
/>
162+
<Mantine.Group position="right" mt="md">
163+
<Mantine.Button
164+
type="submit"
165+
color="orange"
166+
className="bg-orange-400"
167+
disabled={shouldSubmitBeDisabled}
168+
>
169+
Submit
170+
</Mantine.Button>
171+
</Mantine.Group>
172+
</Mantine.ScrollArea>
173+
</form>
174+
</Mantine.Box>
175+
<Mantine.Modal
176+
opened={modalOpened}
177+
onClose={() => {
178+
setModalOpened(false);
179+
setOpened(false); // Close the drawer
180+
}}
181+
title={<Mantine.Title order={2}>Analytics View</Mantine.Title>}
182+
size="70%"
183+
>
184+
<Mantine.Button
185+
onClick={() => setChartToggle()}
186+
color="blue"
187+
className=" justify-center items-center mb-8 w-1/2 text-center bg-orange-400 hover:bg-orange-300"
188+
>
189+
{chartToggle.toUpperCase()}
190+
</Mantine.Button>
191+
<Mantine.Paper className="h-96 bg-lime-200">
192+
{chartToggle === 'pie' && <PieChart data={pieChartData} />}
193+
{chartToggle === 'bar' && <BarChart data={barChartData} />}
194+
</Mantine.Paper>
195+
</Mantine.Modal>
196+
</>
197+
);
198+
}
199+
200+
// Props Validation
201+
AnalyticsForm.propTypes = {
202+
setOpened: PropTypes.func.isRequired,
203+
setAnalyticsButtonDisabled: PropTypes.func.isRequired,
204+
};
205+
206+
export default AnalyticsForm;

Track 4_ReactJS_Web Development/Project/Frontend/hrc-dashboard/src/utils/api/getAnalyticsData.js

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { post } from 'axios';
22

3-
const getAnalyticsData = async (/* payload */) => {
3+
const getAnalyticsData = async (payload) => {
44
const { REACT_APP_API_SERVER, REACT_APP_API_SERVER_PORT } = process.env;
5-
const payload = {
5+
/* const payload = {
66
clear_date: ['2019-01-01', '2020-12-31'],
77
due_in_date: ['2019-01-01', '2020-12-31'],
88
baseline_create_date: ['2019-01-01', '2020-12-31'],
99
invoice_currency: 'USD',
10-
};
10+
}; */
1111

1212
try {
1313
const { status, data } = await post(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
const formInputFields = [
2+
{
3+
htmlFor: 'invoice_currency',
4+
label: 'Invoice Currency',
5+
placeholder: 'Invoice Currency (₹)',
6+
type: 'text',
7+
required: true,
8+
},
9+
];
10+
11+
const formDateFields = [
12+
{
13+
htmlFor: 'clear_date_start',
14+
label: 'Clear Date',
15+
required: true,
16+
placeholder: 'Pick a Clear Date',
17+
type: 'db_date',
18+
},
19+
{
20+
htmlFor: 'clear_date_end',
21+
label: 'Clear Date (END)',
22+
required: true,
23+
placeholder: 'Pick a Clear Date',
24+
type: 'db_date',
25+
},
26+
{
27+
htmlFor: 'due_in_date_start',
28+
label: 'Due Date',
29+
required: true,
30+
placeholder: 'Pick a Due Date',
31+
type: 'db_date',
32+
},
33+
{
34+
htmlFor: 'due_in_date_end',
35+
label: 'Due Date (END)',
36+
required: true,
37+
placeholder: 'Pick a Due Date',
38+
type: 'db_date',
39+
},
40+
{
41+
htmlFor: 'baseline_create_date_start',
42+
label: 'Baseline Create Date',
43+
required: true,
44+
placeholder: 'Pick a Baseline Create Date',
45+
type: 'db_date',
46+
},
47+
{
48+
htmlFor: 'baseline_create_date_end',
49+
label: 'Baseline Create Date (END)',
50+
required: true,
51+
placeholder: 'Pick a Baseline Create Date',
52+
type: 'db_date',
53+
},
54+
];
55+
56+
// Convert '2018-01-01' to Date object
57+
const convertDateToObject = (date) => {
58+
const dateArray = date.split('-');
59+
const year = dateArray[0];
60+
const month = dateArray[1];
61+
const day = dateArray[2];
62+
return new Date(year, month - 1, day);
63+
};
64+
65+
const defaultTableSchema = {
66+
invoice_currency: 'INR',
67+
clear_date_start: convertDateToObject('2020-06-01'),
68+
clear_date_end: convertDateToObject('2020-12-31'),
69+
due_in_date_start: convertDateToObject('2020-06-01'),
70+
due_in_date_end: convertDateToObject('2020-12-31'),
71+
baseline_create_date_start: convertDateToObject('2020-06-01'),
72+
baseline_create_date_end: convertDateToObject('2020-12-31'),
73+
};
74+
75+
export { formInputFields, defaultTableSchema, formDateFields };

0 commit comments

Comments
 (0)