From 5bdfc347c20bf7c7f4b75eecb10497eddcec53f0 Mon Sep 17 00:00:00 2001 From: SebassNoob Date: Mon, 6 May 2024 16:57:56 +0800 Subject: [PATCH] feat: WIP frontend --- .../AttendanceExportsForm.tsx} | 78 ++++++------ .../app/exports/ExportsCard/ExportsCard.tsx | 29 +++++ .../src/app/exports/ExportsForm/styles.css | 6 - .../ServiceHoursExportsForm.tsx | 115 ++++++++++++++++++ interapp-frontend/src/app/exports/page.tsx | 10 +- 5 files changed, 186 insertions(+), 52 deletions(-) rename interapp-frontend/src/app/exports/{ExportsForm/ExportsForm.tsx => AttendanceExportsForm/AttendanceExportsForm.tsx} (69%) create mode 100644 interapp-frontend/src/app/exports/ExportsCard/ExportsCard.tsx delete mode 100644 interapp-frontend/src/app/exports/ExportsForm/styles.css create mode 100644 interapp-frontend/src/app/exports/ServiceHoursExportsForm/ServiceHoursExportsForm.tsx diff --git a/interapp-frontend/src/app/exports/ExportsForm/ExportsForm.tsx b/interapp-frontend/src/app/exports/AttendanceExportsForm/AttendanceExportsForm.tsx similarity index 69% rename from interapp-frontend/src/app/exports/ExportsForm/ExportsForm.tsx rename to interapp-frontend/src/app/exports/AttendanceExportsForm/AttendanceExportsForm.tsx index 53084f94..1e6bbf68 100644 --- a/interapp-frontend/src/app/exports/ExportsForm/ExportsForm.tsx +++ b/interapp-frontend/src/app/exports/AttendanceExportsForm/AttendanceExportsForm.tsx @@ -7,18 +7,18 @@ import { APIClient } from '@api/api_client'; import { Service } from '@/app/services/types'; import { use, useMemo, useState } from 'react'; import { parseServerError } from '@utils/.'; -import './styles.css'; +import { ExportsCard, downloadFile, type DownloadFileHeaders } from '../ExportsCard/ExportsCard'; -type ExportsProps = { +type AttendanceExportsProps = { names: string[]; range: [Date | null, Date | null]; }; -interface ExportsFormProps { +interface AttendanceExportsFormProps { allServices: Promise[]>; } -export function ExportsForm({ allServices }: ExportsFormProps) { +export function AttendanceExportsForm({ allServices }: AttendanceExportsFormProps) { const [enabledDateSelection, setEnabledDateSelection] = useState(false); const [loading, setLoading] = useState(false); const services = use(allServices); @@ -35,7 +35,7 @@ export function ExportsForm({ allServices }: ExportsFormProps) { [services], ); - const form = useForm({ + const form = useForm({ initialValues: { names: [], range: [null, null], @@ -70,7 +70,7 @@ export function ExportsForm({ allServices }: ExportsFormProps) { }, }); - const handleSubmit = async (values: ExportsProps) => { + const handleSubmit = async (values: AttendanceExportsProps) => { const transformedValues = { id: values.names.map((name) => serviceData[name]), start_date: values.range[0]?.toISOString(), @@ -125,17 +125,7 @@ export function ExportsForm({ allServices }: ExportsFormProps) { return; } - const responseData = response.data as ArrayBuffer; - const blob = new Blob([responseData], { type: response.headers['content-type'] }); - - const url = URL.createObjectURL(blob); - const a = document.createElement('a'); - a.href = url; - a.download = response.headers['content-disposition'].split('=')[1]; - a.click(); - a.remove(); - - URL.revokeObjectURL(url); + downloadFile(response.data as ArrayBuffer, response.headers as DownloadFileHeaders); notifications.show({ title: 'Success', @@ -145,33 +135,35 @@ export function ExportsForm({ allServices }: ExportsFormProps) { }; return ( -
- - - { - form.setValues({ range: [null, null] }); - setEnabledDateSelection(!enabledDateSelection); - }} - /> - {enabledDateSelection && ( - + + - )} - - + { + form.setValues({ range: [null, null] }); + setEnabledDateSelection(!enabledDateSelection); + }} + /> + {enabledDateSelection && ( + + )} + + + + ); } diff --git a/interapp-frontend/src/app/exports/ExportsCard/ExportsCard.tsx b/interapp-frontend/src/app/exports/ExportsCard/ExportsCard.tsx new file mode 100644 index 00000000..9cf839f0 --- /dev/null +++ b/interapp-frontend/src/app/exports/ExportsCard/ExportsCard.tsx @@ -0,0 +1,29 @@ +import { Card, Stack } from '@mantine/core'; +import { AxiosResponseHeaders } from 'axios'; +import { type ReactNode } from 'react'; + +export interface DownloadFileHeaders extends AxiosResponseHeaders { + 'content-type': string; + 'content-disposition': string; +} + +export function downloadFile(data: ArrayBuffer, headers: DownloadFileHeaders) { + const blob = new Blob([data], { type: headers['content-type'] }); + + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = headers['content-disposition'].split('=')[1]; + a.click(); + a.remove(); + + URL.revokeObjectURL(url); +} + +export function ExportsCard({ children }: { children: ReactNode }) { + return ( + + {children} + + ); +} diff --git a/interapp-frontend/src/app/exports/ExportsForm/styles.css b/interapp-frontend/src/app/exports/ExportsForm/styles.css deleted file mode 100644 index fc62d75c..00000000 --- a/interapp-frontend/src/app/exports/ExportsForm/styles.css +++ /dev/null @@ -1,6 +0,0 @@ -.exports-form { - display: flex; - flex-direction: column; - gap: 1rem; - margin-top: 1rem; -} diff --git a/interapp-frontend/src/app/exports/ServiceHoursExportsForm/ServiceHoursExportsForm.tsx b/interapp-frontend/src/app/exports/ServiceHoursExportsForm/ServiceHoursExportsForm.tsx new file mode 100644 index 00000000..14139ac6 --- /dev/null +++ b/interapp-frontend/src/app/exports/ServiceHoursExportsForm/ServiceHoursExportsForm.tsx @@ -0,0 +1,115 @@ +'use client'; +import { ExportsCard, downloadFile, type DownloadFileHeaders } from '../ExportsCard/ExportsCard'; +import { Select, Button, Group, Text } from '@mantine/core'; +import { useForm } from '@mantine/form'; +import { AxiosInstance } from 'axios'; +import { notifications } from '@mantine/notifications'; + +interface ServiceExportsProps { + type: 'user_id' | 'username' | 'service_hours'; + order: 'ASC' | 'DESC'; +} + +interface UserFriendlyServiceExportsProps { + type: (typeof types)[number]; + order: (typeof orders)[number]; +} + +const types = ['User ID', 'Username', 'CCA Hours'] as const; +const orders = ['Ascending', 'Descending'] as const; + +const test = async (apiClient: AxiosInstance) => { + const response = await apiClient.get('/exports/service_hours', { + params: { + type: 'username', + order: 'ASC', + }, + responseType: 'arraybuffer', + }); + console.log(response.data); + const responseData = response.data as ArrayBuffer; + const blob = new Blob([responseData], { type: response.headers['content-type'] }); + + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = response.headers['content-disposition'].split('=')[1]; + a.click(); + a.remove(); + + URL.revokeObjectURL(url); + console.log(a.href); +}; + +const normaliseServiceExportsProps = ( + props: UserFriendlyServiceExportsProps, +): ServiceExportsProps => { + let type: ServiceExportsProps['type']; + let order: ServiceExportsProps['order']; + + switch (props.type) { + case 'User ID': + type = 'user_id'; + break; + case 'Username': + type = 'username'; + break; + case 'CCA Hours': + type = 'service_hours'; + break; + } + + switch (props.order) { + case 'Ascending': + order = 'ASC'; + break; + case 'Descending': + order = 'DESC'; + break; + } + + return { type, order }; +}; + +const initialType = types[0]; +const initialOrder = orders[0]; + +export function ServiceHoursExportsForm() { + const form = useForm({ + initialValues: { + type: initialType, + order: initialOrder, + }, + }); + + const handleSubmit = async (values: UserFriendlyServiceExportsProps) => { + console.log(values); + }; + + return ( + +
+ + Sort users by... + + + +
+
+ ); +} diff --git a/interapp-frontend/src/app/exports/page.tsx b/interapp-frontend/src/app/exports/page.tsx index aa7ef491..2f49af9b 100644 --- a/interapp-frontend/src/app/exports/page.tsx +++ b/interapp-frontend/src/app/exports/page.tsx @@ -2,12 +2,13 @@ export const dynamic = 'force-dynamic'; // nextjs needs this to build properly import APIClient from '@api/api_client'; import { useMemo } from 'react'; -import { Title, Text } from '@mantine/core'; +import { Title, Text, Group } from '@mantine/core'; import { type Service } from '@/app/services/types'; import { AxiosInstance } from 'axios'; import './styles.css'; -import { ExportsForm } from './ExportsForm/ExportsForm'; +import { AttendanceExportsForm } from './AttendanceExportsForm/AttendanceExportsForm'; +import { ServiceHoursExportsForm } from './ServiceHoursExportsForm/ServiceHoursExportsForm'; import { ClientError } from '@utils/.'; const fetchServices = async (apiClient: AxiosInstance) => { @@ -35,7 +36,10 @@ export default function Exports() {
Exports Export data as an Excel sheet here. - + + + +
); }