minor fixes

This commit is contained in:
2026-01-11 10:51:28 -06:00
parent 41e9ae33dc
commit 51de91f8d4
16 changed files with 558 additions and 1440 deletions

View File

@@ -14,7 +14,6 @@
"@fortawesome/fontawesome-svg-core": "^7.1.0", "@fortawesome/fontawesome-svg-core": "^7.1.0",
"@fortawesome/free-solid-svg-icons": "^7.1.0", "@fortawesome/free-solid-svg-icons": "^7.1.0",
"@fortawesome/react-fontawesome": "^3.1.0", "@fortawesome/react-fontawesome": "^3.1.0",
"@noahspan/noahspan-components": "^2.0.0-alpha-14",
"@tailwindcss/typography": "^0.5.19", "@tailwindcss/typography": "^0.5.19",
"@tailwindcss/vite": "^4.1.13", "@tailwindcss/vite": "^4.1.13",
"@tanstack/react-table": "^8.21.3", "@tanstack/react-table": "^8.21.3",

View File

@@ -1,93 +0,0 @@
import { useState } from 'react';
import { IActionMenuProps } from './IActionMenuProps';
import {
IconButton,
Icon,
IconName,
Dropdown
} from '@noahspan/noahspan-components';
import { FormMode } from '../../enums/formMode';
import { useAuth } from 'react-oidc-context';
const ActionMenu = ({ id, onDelete, onOpenCloseForm, onOpenCloseTracks }: IActionMenuProps) => {
// const [anchorElAction, setAnchorElAction] = useState<null | HTMLElement>(
// null
// );
// const auth = useAuth();
// const onOpenActionMenu = (event: React.MouseEvent<HTMLElement>) => {
// setAnchorElAction(event.currentTarget);
// };
// const onCloseActionMenu = () => {
// setAnchorElAction(null);
// };
const options = [
'Item 1',
'Item 2'
]
return (
<>
<Dropdown
onOptionSelected={() => console.log('clicked!')}
options={options}
>
<IconButton>
<Icon className='text-2xl' iconName={IconName.ELLIPSIS_VERTICAL} />
</IconButton>
</Dropdown>
</>
// <div>
// <IconButton onClick={onOpenActionMenu}>
// <Icon iconName={IconName.ELLIPSIS_VERTICAL} size="sm" />
// </IconButton>
// <Menu
// anchorEl={anchorElAction}
// keepMounted
// open={Boolean(anchorElAction)}
// onClose={onCloseActionMenu}
// >
// {auth.isAuthenticated &&
// <>
// <MenuItem onClick={() => onOpenCloseForm(FormMode.EDIT, id)}>
// <ListItemIcon>
// <Icon iconName={IconName.PEN} size="lg" />
// </ListItemIcon>
// <ListItemText>Edit</ListItemText>
// </MenuItem>
// {onOpenCloseTracks &&
// <MenuItem onClick={() => onOpenCloseTracks!(FormMode.EDIT, id)}>
// <ListItemIcon>
// <Icon iconName={IconName.MAP_LOCATION_DOT} size="lg" />
// </ListItemIcon>
// <ListItemText>Tracks</ListItemText>
// </MenuItem>
// }
// </>
// }
// <MenuItem onClick={() => onOpenCloseForm(FormMode.VIEW, id)}>
// <ListItemIcon>
// <Icon iconName={IconName.EYE} size="lg" />
// </ListItemIcon>
// <ListItemText>View</ListItemText>
// </MenuItem>
// {auth.isAuthenticated &&
// <>
// <hr className="my-3" />
// <MenuItem onClick={() => onDelete(id)}>
// <ListItemIcon>
// <Icon iconName={IconName.TRASH} size="lg" />
// </ListItemIcon>
// <ListItemText>Delete</ListItemText>
// </MenuItem>
// </>
// }
// </Menu>
// </div>
);
};
export default ActionMenu;

View File

@@ -1,8 +0,0 @@
import { FormMode } from '../../enums/formMode';
export interface IActionMenuProps {
id: string;
onDelete: (entryId: string) => void;
onOpenCloseForm: (formMode: FormMode, id: string) => void;
onOpenCloseTracks?: (formMode: FormMode, id: string) => void;
}

View File

@@ -48,29 +48,17 @@ const Flights = () => {
<LogbookCard logs={state.flights} mode='flights' /> <LogbookCard logs={state.flights} mode='flights' />
</div> </div>
} }
{/* {logsLoading && [...Array(6)].map((_element, index) => { {logsLoading && [...Array(5)].map((_element, index) => {
return ( return (
<div className='mb-5'> <div className='card bg-base-100 border border-base-300 p-2 mb-7'>
<Card <div className='card-body' key={index}>
key={index} <div className='skeleton h-10 w-[150px]' />
> <div className='skeleton h-[350px]' />
<div className='p-5'> <div className='skeleton h-[65px]' />
<div className='mb-2'><Skeleton height='h-[60px]' width='w-[200px]' /></div> </div>
<div className='mb-2'><Skeleton height='h-[30px]' width='w-[200px]' /></div>
<div className='mb-2'><Skeleton height='h-[300px]' width='w-[300px]' /></div>
{[...Array(4)].map((_element, index) => {
return (
<>
<div className='mb-2'><Skeleton height='h-[20px]' width='w-[300px]' /></div>
<div className='mb-2'><Skeleton height='h-[20px]' width='w-[300px]' /></div>
</>
)
})}
</div>
</Card>
</div> </div>
) )
})} */} })}
</div> </div>
) )
} }

View File

@@ -1,8 +1,7 @@
import { useEffect, useReducer } from 'react'; import { useEffect, useReducer, useState } from 'react';
import { initialState, reducer } from './reducer'; import { initialState, reducer } from './reducer';
import { AxiosError, AxiosResponse } from 'axios'; import { AxiosError, AxiosResponse } from 'axios';
import { FormMode } from '../../enums/formMode'; import { FormMode } from '../../enums/formMode';
import { authColumns, unauthColumns } from './columns';
import ConfirmationDialog from '../confirmationDialog/ConfirmationDialog'; import ConfirmationDialog from '../confirmationDialog/ConfirmationDialog';
import { LogbookEntry } from './LogbookEntry.interface'; import { LogbookEntry } from './LogbookEntry.interface';
import LogbookCard from '../logbookCard/LogbookCard'; import LogbookCard from '../logbookCard/LogbookCard';
@@ -21,6 +20,7 @@ import Alert from '../alert/Alert';
const Logbook: React.FC<unknown> = () => { const Logbook: React.FC<unknown> = () => {
const [state, dispatch] = useReducer(reducer, initialState); const [state, dispatch] = useReducer(reducer, initialState);
const [columnVisibility, setColumnVisibility] = useState({})
const logbookContext = useLogbookContext() const logbookContext = useLogbookContext()
const { isUserLoggedIn } = useOidc(); const { isUserLoggedIn } = useOidc();
const { userRole } = useUserRole(); const { userRole } = useUserRole();
@@ -51,7 +51,7 @@ const Logbook: React.FC<unknown> = () => {
accessorKey: 'date', accessorKey: 'date',
header: 'Date', header: 'Date',
cell: (info: CellContext<LogbookEntry, unknown>) => { cell: (info: CellContext<LogbookEntry, unknown>) => {
const date = new Date(info.getValue() as string); const date = new Date((info.getValue() as string).replace('Z', ''));
const formattedDate = `${date.getMonth() + 1}/${date.getDate()}/${date.getFullYear()}` const formattedDate = `${date.getMonth() + 1}/${date.getDate()}/${date.getFullYear()}`
return formattedDate; return formattedDate;
@@ -118,7 +118,7 @@ const Logbook: React.FC<unknown> = () => {
return ( return (
<div className='dropdown dropdown-end'> <div className='dropdown dropdown-end'>
<div tabIndex={0} role='button' className='btn btn-ghost'><FontAwesomeIcon icon={faEllipsisVertical} /></div> <div tabIndex={0} role='button' className='btn btn-ghost'><FontAwesomeIcon icon={faEllipsisVertical} /></div>
<ul tabIndex={-1} className="dropdown-content menu bg-base-100 rounded-box z-1 w-52 p-2 shadow-sm border border-base-300"> <ul tabIndex={-1} className="dropdown-content menu bg-base-100 rounded-box w-52 p-2 shadow-sm border border-base-300 !z-[100]">
{isUserLoggedIn && userRole === UserRole.WRITE && {isUserLoggedIn && userRole === UserRole.WRITE &&
<li><a onClick={() => onOpenCloseDrawer(FormMode.EDIT, info.row.original.id)}><FontAwesomeIcon icon={faPen} />Edit</a></li> <li><a onClick={() => onOpenCloseDrawer(FormMode.EDIT, info.row.original.id)}><FontAwesomeIcon icon={faPen} />Edit</a></li>
} }
@@ -132,16 +132,7 @@ const Logbook: React.FC<unknown> = () => {
} }
} }
const unauthColumns: ColumnDef<LogbookEntry>[] = [ const columns: ColumnDef<LogbookEntry>[] = [
pilotName,
date,
aircraftMakeModel,
route,
durationOfFlight,
notes
]
const authColumns: ColumnDef<LogbookEntry>[] = [
pilotName, pilotName,
date, date,
aircraftMakeModel, aircraftMakeModel,
@@ -345,18 +336,46 @@ const Logbook: React.FC<unknown> = () => {
}, },
notes, notes,
actions actions
] ];
const table = useReactTable({
data: state.entries,
columns: columns,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel(),
onColumnVisibilityChange: setColumnVisibility,
state: {
columnVisibility: columnVisibility
}
});
const getLogbookEntries = async () => { const getLogbookEntries = async () => {
try { try {
dispatch({ type: 'SET_IS_LOADING', payload: true }); dispatch({ type: 'SET_IS_LOADING', payload: true });
const response: AxiosResponse = await httpClient.get(`api/logs`); const response: AxiosResponse = await httpClient.get(`api/logs`);
const entries: LogbookEntry[] = response.data;
entries.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime())
if (response.data.length > 0) { if (response.data.length > 0) {
dispatch({ type: 'SET_ENTRIES', payload: response.data }); const entries: LogbookEntry[] = response.data;
const entryColumns: string[] = Object.keys(entries[0]);
const columnVisibility: {[key: string]: boolean} = {}
for (const column of table.getAllLeafColumns()) {
const entryColumnExists = entryColumns.find((entryColumn) => entryColumn === column.id);
if (entryColumnExists) {
columnVisibility[column.id] = true
} else {
columnVisibility[column.id] = false
}
}
columnVisibility['pilotName'] = true
columnVisibility['actions'] = true
entries.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());
setColumnVisibility(columnVisibility)
dispatch({ type: 'SET_ENTRIES', payload: entries });
if (state.alert) { if (state.alert) {
dispatch({ type: 'SET_ALERT', payload: undefined}) dispatch({ type: 'SET_ALERT', payload: undefined})
@@ -441,44 +460,6 @@ const Logbook: React.FC<unknown> = () => {
}); });
}; };
// useEffect(() => {
// let newColumns: ColumnDef<LogbookEntry>[];
// if (userRole === UserRole.WRITE) {
// newColumns = [...authColumns];
// } else {
// newColumns = [...unauthColumns];
// }
// const actionsColumnExists = newColumns.find((column) => column.id === 'actions');
// const tracksColumnExists = newColumns.find((column) => column.id === 'actions');
// if (!actionsColumnExists) {
// newColumns.push(actionsColumn);
// }
// if (!tracksColumnExists) {
// const notesColumnIndex = newColumns.findIndex((column) => column.id === 'notes')
// newColumns.splice(notesColumnIndex, 0, tracksColumn)
// }
// dispatch({ type: 'SET_COLUMNS', payload: newColumns })
// }, [isUserLoggedIn])
const table = useReactTable({
data: state.entries,
columns: authColumns,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel()
});
const textAlignment = {
center: 'text-center',
left: 'text-start',
right: 'text-end'
};
useEffect(() => { useEffect(() => {
if (!logbookContext.state.isDrawerOpen) { if (!logbookContext.state.isDrawerOpen) {
getLogbookEntries(); getLogbookEntries();
@@ -493,14 +474,6 @@ const Logbook: React.FC<unknown> = () => {
</div> </div>
<div className='col-span-2 justify-self-end self-center'> <div className='col-span-2 justify-self-end self-center'>
{userRole === UserRole.WRITE && {userRole === UserRole.WRITE &&
// <Button
// color='primary'
// onPress={() => onOpenCloseDrawer(FormMode.ADD)}
// startContent={<FontAwesomeIcon icon={faAdd} />}
// data-testid="pilot-add-button"
// >
// Add Entry
// </Button>
<button className='btn btn-primary' <button className='btn btn-primary'
onClick={() => onOpenCloseDrawer(FormMode.ADD)} onClick={() => onOpenCloseDrawer(FormMode.ADD)}
> >
@@ -522,111 +495,109 @@ const Logbook: React.FC<unknown> = () => {
</Alert> </Alert>
</div> </div>
)} )}
{!state.isLoading && ( {!state.isLoading && state.entries.length > 0 && screenSize !== ScreenSize.SM && (
<div className='col-span-12 p-5 bg-base-100 border border-base-100 rounded-lg'> <div className='col-span-12 p-5 bg-base-100 border border-base-100 rounded-lg'>
{state.entries.length > 0 && screenSize !== ScreenSize.SM && ( <div className='overflow-x-auto'>
<div className='overflow-x-auto'> <table className='table min-w-full h-auto table-auto w-full'>
<table className='table min-w-full h-auto table-auto w-full'> <thead className='bg-base-200'>
<thead className='bg-base-200'> {table.getHeaderGroups().map((headerGroup, headerGroupIndex) => (
{table.getHeaderGroups().map((headerGroup, headerGroupIndex) => ( <tr className='group/tr outline-solid outline-transparent data-[focus-visible=true]:z-10 data-[focus-visible=true]:outline-2 data-[focus-visible=true]:outline-focus data-[focus-visible=true]:outline-offset-2' key={headerGroup.id}>
<tr className='group/tr outline-solid outline-transparent data-[focus-visible=true]:z-10 data-[focus-visible=true]:outline-2 data-[focus-visible=true]:outline-focus data-[focus-visible=true]:outline-offset-2' key={headerGroup.id}> {headerGroup.headers.map((header, headerIndex) => {
{headerGroup.headers.map((header, headerIndex) => {
return (
<th
className={`${header.column.columnDef.meta?.className ? header.column.columnDef.meta?.className : ''} group/th px-3 h-10 align-middle whitespace-nowrap text-foreground-500 text-tiny font-semibold ${headerGroupIndex === 0 ? 'first:rounded-tl-lg last:rounded-tr-lg' : ''} ${headerGroupIndex === table.getHeaderGroups().length - 1 ? 'first:rounded-bl-lg last:rounded-br-lg' : ''} data-[sortable=true]:cursor-pointer data-[hover=true]:text-foreground-400 outline-solid outline-transparent data-[focus-visible=true]:z-10 data-[focus-visible=true]:outline-2 data-[focus-visible=true]:outline-focus data-[focus-visible=true]:outline-offset-2 text-start`}
colSpan={header.colSpan}
key={header.id}
>
{header.isPlaceholder ? null : (
<div className={`${header.column.columnDef.meta?.headerAlign ? header.column.columnDef.meta?.headerAlign : ''}`}>
{flexRender(
header.column.columnDef.header,
header.getContext()
)}
{/* {header.column.getCanFilter() ? (
<div>
<Filter column={header.column} table={table} />
</div>
) : null} */}
</div>
)}
</th>
);
})}
</tr>
))}
</thead>
<tbody>
<>
{table.getRowModel().rows.map((row) => {
return ( return (
<tr className='group/tr outline-solid outline-transparent data-[focus-visible=true]:z-10 data-[focus-visible=true]:outline-2 data-[focus-visible=true]:outline-focus data-[focus-visible=true]:outline-offset-2' key={row.id}> <th
{row.getVisibleCells().map((cell) => { className={`${header.column.columnDef.meta?.className ? header.column.columnDef.meta?.className : ''} group/th px-3 h-10 align-middle whitespace-nowrap text-foreground-500 text-tiny font-semibold ${headerGroupIndex === 0 ? 'first:rounded-tl-lg last:rounded-tr-lg' : ''} ${headerGroupIndex === table.getHeaderGroups().length - 1 ? 'first:rounded-bl-lg last:rounded-br-lg' : ''} data-[sortable=true]:cursor-pointer data-[hover=true]:text-foreground-400 outline-solid outline-transparent data-[focus-visible=true]:z-10 data-[focus-visible=true]:outline-2 data-[focus-visible=true]:outline-focus data-[focus-visible=true]:outline-offset-2 text-start`}
return ( colSpan={header.colSpan}
<td key={header.id}
className={`py-2 px-3 relative align-middle whitespace-normal text-small font-normal [&>*]:z-1 [&>*]:relative outline-solid outline-transparent data-[focus-visible=true]:z-10 data-[focus-visible=true]:outline-2 data-[focus-visible=true]:outline-focus data-[focus-visible=true]:outline-offset-2 before:pointer-events-none before:content-[''] before:absolute before:z-0 before:inset-0 before:opacity-0 data-[selected=true]:before:opacity-100 group-data-[disabled=true]/tr:text-foreground-300 group-data-[disabled=true]/tr:cursor-not-allowed before:bg-default/60 data-[selected=true]:text-default-foreground first:before:rounded-s-lg last:before:rounded-e-lg text-start`} >
key={cell.id} {header.isPlaceholder ? null : (
> <div className={`${header.column.columnDef.meta?.headerAlign ? header.column.columnDef.meta?.headerAlign : ''}`}>
<div className={`${cell.column.columnDef.meta?.align ? cell.column.columnDef.meta?.align : ''}`}> {flexRender(
{flexRender( header.column.columnDef.header,
cell.column.columnDef.cell, header.getContext()
cell.getContext() )}
)} {/* {header.column.getCanFilter() ? (
<div>
<Filter column={header.column} table={table} />
</div> </div>
</td> ) : null} */}
); </div>
})} )}
</tr> </th>
); );
})} })}
</> </tr>
</tbody> ))}
<thead className='[&>tr]:first:rounded-lg bg-base-200'> </thead>
{table.getFooterGroups().map((footerGroup, index) => { <tbody>
if (index === 0) { <>
return ( {table.getRowModel().rows.map((row) => {
<tr className='group/tr outline-solid outline-transparent data-[focus-visible=true]:z-10 data-[focus-visible=true]:outline-2 data-[focus-visible=true]:outline-focus data-[focus-visible=true]:outline-offset-2' key={footerGroup.id}> return (
{footerGroup.headers.map((header) => { <tr className='group/tr outline-solid outline-transparent data-[focus-visible=true]:z-10 data-[focus-visible=true]:outline-2 data-[focus-visible=true]:outline-focus data-[focus-visible=true]:outline-offset-2' key={row.id}>
return ( {row.getVisibleCells().map((cell) => {
<td return (
className='group/th px-3 h-10 align-middle bg-default-100 whitespace-nowrap text-foreground-500 text-tiny font-semibold first:rounded-s-lg last:rounded-e-lg data-[sortable=true]:cursor-pointer data-[hover=true]:text-foreground-400 outline-solid outline-transparent data-[focus-visible=true]:z-10 data-[focus-visible=true]:outline-2 data-[focus-visible=true]:outline-focus data-[focus-visible=true]:outline-offset-2 text-start' <td
key={header.id} className={`py-2 px-3 relative align-middle whitespace-normal text-small font-normal [&>*]:relative outline-solid outline-transparent data-[focus-visible=true]:z-10 data-[focus-visible=true]:outline-2 data-[focus-visible=true]:outline-focus data-[focus-visible=true]:outline-offset-2 before:pointer-events-none before:content-[''] before:absolute before:z-0 before:inset-0 before:opacity-0 data-[selected=true]:before:opacity-100 group-data-[disabled=true]/tr:text-foreground-300 group-data-[disabled=true]/tr:cursor-not-allowed before:bg-default/60 data-[selected=true]:text-default-foreground first:before:rounded-s-lg last:before:rounded-e-lg text-start`}
> key={cell.id}
<div className={`${header.column.columnDef.meta?.headerAlign ? header.column.columnDef.meta?.headerAlign : ''}`}> >
{header.isPlaceholder <div className={`${cell.column.columnDef.meta?.align ? cell.column.columnDef.meta?.align : ''}`}>
? null {flexRender(
: flexRender( cell.column.columnDef.cell,
header.column.columnDef.footer, cell.getContext()
header.getContext() )}
) </div>
} </td>
</div> );
</td> })}
); </tr>
})} );
</tr>
);
}
})} })}
</thead> </>
</table> </tbody>
</div> <thead className='[&>tr]:first:rounded-lg bg-base-200'>
)} {table.getFooterGroups().map((footerGroup, index) => {
{state.entries.length > 0 && screenSize === ScreenSize.SM && if (index === 0) {
<LogbookCard logs={state.entries} onDelete={onDeleteLog} mode='logbook' onOpenCloseForm={onOpenCloseDrawer} /> return (
} <tr className='group/tr outline-solid outline-transparent data-[focus-visible=true]:z-10 data-[focus-visible=true]:outline-2 data-[focus-visible=true]:outline-focus data-[focus-visible=true]:outline-offset-2' key={footerGroup.id}>
{footerGroup.headers.map((header) => {
return (
<td
className='roup/th px-3 h-10 align-middle bg-default-100 whitespace-nowrap text-foreground-500 text-tiny font-semibold first:rounded-s-lg last:rounded-e-lg data-[sortable=true]:cursor-pointer data-[hover=true]:text-foreground-400 outline-solid outline-transparent data-[focus-visible=true]:z-10 data-[focus-visible=true]:outline-2 data-[focus-visible=true]:outline-focus data-[focus-visible=true]:outline-offset-2 text-start'
key={header.id}
>
<div className={`${header.column.columnDef.meta?.headerAlign ? header.column.columnDef.meta?.headerAlign : ''}`}>
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.footer,
header.getContext()
)
}
</div>
</td>
);
})}
</tr>
);
}
})}
</thead>
</table>
</div>
</div> </div>
)} )}
{/* {state.isLoading && !state.alert && ( {state.entries.length > 0 && screenSize === ScreenSize.SM &&
<> <LogbookCard logs={state.entries} onDelete={onDeleteLog} mode='logbook' onOpenCloseForm={onOpenCloseDrawer} />
<div> }
<Loading size='xl' /> {state.isLoading && !state.alert && (
<div className='col-span-12 p-5 bg-base-100 border border-base-100 rounded-lg'>
<div className='col-span-12 justify-self-center'>
<span className='loading loading-spinner loading-xl' />
</div> </div>
<div> <div className='col-span-12 justify-self-center'>
Loading... Loading...
</div> </div>
</> </div>
)} */} )}
</div> </div>
{logbookContext.state.isDrawerOpen && ( {logbookContext.state.isDrawerOpen && (
<LogbookDrawer <LogbookDrawer

View File

@@ -1,291 +0,0 @@
import {
CellContext,
ColumnDef,
HeaderContext,
} from '@noahspan/noahspan-components';
import { LogbookEntry } from './LogbookEntry.interface';
const columnTotal = (info: HeaderContext<LogbookEntry, unknown>): number => {
const blah = info.table
const values: number[] = info.table.getPaginationRowModel().rows.map((row: any) => Number(row.getValue(info.column.id))).filter((value: any) => !Number.isNaN(value));
let total: number = 0;
if (values.length > 0) {
total = values.reduce((accumulator, currentValue) => accumulator + currentValue, total)
}
return total;
}
const pilotName: ColumnDef<LogbookEntry> = {
id: 'pilotName',
accessorKey: 'pilot',
header: 'Pilot',
footer: 'PAGE TOTALS',
cell: (info: CellContext<LogbookEntry, unknown>) => {
const pilot: any = info.getValue();
return pilot.name
}
}
const date: ColumnDef<LogbookEntry> = {
id: 'date',
accessorKey: 'date',
header: 'Date',
cell: (info: CellContext<LogbookEntry, unknown>) => {
const date = new Date(info.getValue() as string);
const formattedDate = `${date.getMonth() + 1}/${date.getDate()}/${date.getFullYear()}`
return formattedDate;
}
}
const aircraftMakeModel: ColumnDef<LogbookEntry> = {
id: 'aircraftMakeModel',
accessorKey: 'aircraftMakeModel',
header: 'Aircraft Make & Model'
}
const route: ColumnDef<LogbookEntry> = {
id: 'route',
header: 'Route of Flight',
meta: {
headerAlign: 'text-center',
className: 'border-l border-base-400'
},
columns: [
{
id: 'routeFrom',
accessorKey: 'routeFrom',
header: 'From'
},
{
id: 'routeTo',
accessorKey: 'routeTo',
header: 'To'
}
]
}
const durationOfFlight: ColumnDef<LogbookEntry> = {
id: 'durationOfFlight',
accessorKey: 'durationOfFlight',
header: 'Duration Of Flight',
meta: {
align: 'text-right',
headerAlign: 'text-right'
},
cell: (info: CellContext<LogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : '',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : ''
}
const notes: ColumnDef<LogbookEntry> = {
id: 'notes',
accessorKey: 'notes',
header: 'Notes'
}
export const unauthColumns: ColumnDef<LogbookEntry>[] = [
pilotName,
date,
aircraftMakeModel,
route,
durationOfFlight,
notes
]
export const authColumns: ColumnDef<LogbookEntry>[] = [
pilotName,
date,
aircraftMakeModel,
{
id: 'aircraftIdentity',
accessorKey: 'aircraftIdentity',
header: 'Aircraft Identity',
},
route,
durationOfFlight,
{
id: 'singleEngineLand',
accessorKey: 'singleEngineLand',
header: 'Single Engine Land',
meta: {
align: 'text-right',
headerAlign: 'text-right'
},
cell: (info: CellContext<LogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : '',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : ''
},
{
id: 'landings',
header: 'Landings',
meta: {
headerAlign: 'text-center'
},
columns: [
{
id: 'landingsDay',
accessorKey: 'landingsDay',
header: 'Day',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info) : '',
meta: {
align: 'text-right',
headerAlign: 'text-right'
}
},
{
id: 'landingsNight',
accessorKey: 'landingsNight',
header: 'Night',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info) : '',
meta: {
align: 'text-right',
headerAlign: 'text-right'
}
}
]
},
{
id: 'instrument',
header: 'Instrument',
meta: {
headerAlign: 'text-center'
},
columns: [
{
id: 'instrumentActual',
accessorKey: 'instrumentActual',
header: 'Actual',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: {
align: 'text-right',
headerAlign: 'text-right'
},
cell: (info: CellContext<LogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : '',
},
{
id: 'instrumentSimulated',
accessorKey: 'instrumentSimulated',
header: 'Simulated',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: {
align: 'text-right',
headerAlign: 'text-right'
},
cell: (info: CellContext<LogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : ''
},
{
id: 'instrumentApproaches',
accessorKey: 'instrumentApproaches',
header: 'Approaches',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: {
align: 'text-right',
headerAlign: 'text-right'
}
},
{
id: 'instrumentHolds',
accessorKey: 'instrumentHolds',
header: 'Holds',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: {
align: 'text-right',
headerAlign: 'text-right'
}
},
{
id: 'instrumentNavTrack',
accessorKey: 'instrumentNavTrack',
header: 'Nav/Track',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: {
align: 'text-right',
headerAlign: 'text-right'
}
}
]
},
{
id: 'experienceTraining',
header: 'Type of pilot experience or training',
meta: {
headerAlign: 'text-center'
},
columns: [
{
id: 'groundTrainingReceived',
accessorKey: 'groundTrainingReceived',
header: 'Ground Training Received',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: {
align: 'text-right',
headerAlign: 'text-right'
},
cell: (info: CellContext<LogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : ''
},
{
id: 'flightTrainingReceived',
accessorKey: 'flightTrainingReceived',
header: 'Flight Training Received',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: {
align: 'text-right',
headerAlign: 'text-right'
},
cell: (info: CellContext<LogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : ''
},
{
id: 'crossCountry',
accessorKey: 'crossCountry',
header: 'Cross Country',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: {
align: 'text-right',
headerAlign: 'text-right'
},
cell: (info: CellContext<LogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : ''
},
{
id: 'night',
accessorKey: 'night',
header: 'Night',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: {
align: 'text-right',
headerAlign: 'text-right'
},
cell: (info: CellContext<LogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : ''
},
{
id: 'solo',
accessorKey: 'solo',
header: 'Solo',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: {
align: 'text-right',
headerAlign: 'text-right'
},
cell: (info: CellContext<LogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : ''
},
{
id: 'pilotInCommand',
accessorKey: 'pilotInCommand',
header: 'Pilot In Command',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: {
align: 'text-right',
headerAlign: 'text-right'
},
cell: (info: CellContext<LogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : ''
}
]
},
notes
]

View File

@@ -5,8 +5,8 @@ const LogbookCard = ({ logs, mode, onDelete, onOpenCloseForm }: LogbookCardProps
return ( return (
<div> <div>
{logs.map((log) => { {logs.map((log) => {
const date = new Date(log.date); const date = new Date(log.date.replace('Z', ''));
const formattedDate: string = `${date.getMonth()}/${date.getDate()}/${date.getFullYear()}`; const formattedDate: string = `${date.getMonth() + 1}/${date.getDate()}/${date.getFullYear()}`;
return ( return (
<div className='card bg-base-100 border border-base-300 p-2'> <div className='card bg-base-100 border border-base-300 p-2'>

View File

@@ -9,7 +9,7 @@ import { FormMode } from "../../enums/formMode";
import httpClient from "../../httpClient/httpClient"; import httpClient from "../../httpClient/httpClient";
import { AxiosError } from "axios"; import { AxiosError } from "axios";
import { useLogbookContext } from "../../hooks/logbookContext/UseLogbookContext"; import { useLogbookContext } from "../../hooks/logbookContext/UseLogbookContext";
import { useState } from "react"; import { ChangeEventHandler, MouseEventHandler, useState } from "react";
const LogbookDrawer = ({ onOpenClose }: LogbookDrawerProps) => { const LogbookDrawer = ({ onOpenClose }: LogbookDrawerProps) => {
const [activeTab, setActiveTab] = useState<string>('time'); const [activeTab, setActiveTab] = useState<string>('time');
@@ -73,16 +73,12 @@ const LogbookDrawer = ({ onOpenClose }: LogbookDrawerProps) => {
setActiveTab(tab) setActiveTab(tab)
} }
const onTabClicked = (event: any) => {
setActiveTab(event.target.ariaLabel)
}
return ( return (
<div className='drawer drawer-end' <div className='drawer drawer-end'>
// closeButton={
// <Button isIconOnly>
// <FontAwesomeIcon icon={faXmark} />
// </Button>
// }
// isOpen={logbookContext.state.isDrawerOpen}
// onClose={onCancel}
>
<input type='checkbox' className='drawer-toggle' onChange={() => {}} checked={logbookContext.state.isDrawerOpen} /> <input type='checkbox' className='drawer-toggle' onChange={() => {}} checked={logbookContext.state.isDrawerOpen} />
<div className="drawer-side"> <div className="drawer-side">
<label <label
@@ -93,9 +89,18 @@ const LogbookDrawer = ({ onOpenClose }: LogbookDrawerProps) => {
<div className='menu bg-base-100 text-base-content min-h-full p-4' style={{ width: '25%' }}> <div className='menu bg-base-100 text-base-content min-h-full p-4' style={{ width: '25%' }}>
<FormProvider {...methods}> <FormProvider {...methods}>
<form className='prose max-w-none' onSubmit={methods.handleSubmit(onSubmit)} style={{ paddingBottom: '50px' }}> <form className='prose max-w-none' onSubmit={methods.handleSubmit(onSubmit)} style={{ paddingBottom: '50px' }}>
<h2> <div className='grid grid-cols-12 mb-6'>
{`${logbookContext.state.formMode.toString().toLowerCase().charAt(0).toUpperCase() + logbookContext.state.formMode.toString().slice(1).toLowerCase()} Entry`} <div className="col-span-10">
</h2> <h2 className="mt-0 mb-0 self-center">
{`${logbookContext.state.formMode.toString().toLowerCase().charAt(0).toUpperCase() + logbookContext.state.formMode.toString().slice(1).toLowerCase()} Entry`}
</h2>
</div>
<div className="col-span-2 justify-self-end self-center">
<button className="btn btn-ghost" onClick={onCancel}>
<FontAwesomeIcon icon={faXmark} />
</button>
</div>
</div>
{logbookContext.state.formAlert && ( {logbookContext.state.formAlert && (
<Alert <Alert
className='mb-5' className='mb-5'
@@ -109,7 +114,7 @@ const LogbookDrawer = ({ onOpenClose }: LogbookDrawerProps) => {
)} )}
<div className='tabs tabs-lift mb-5'> <div className='tabs tabs-lift mb-5'>
<label className='tab'> <label className='tab'>
<input type='radio' name='my_tabs' defaultChecked={true} /> <input aria-label='time' type='radio' name='logbook_drawer_tabs' onChange={onTabClicked} checked={activeTab === 'time' ? true : false} />
<FontAwesomeIcon className='mr-1'icon={faClock} /> <FontAwesomeIcon className='mr-1'icon={faClock} />
Time Time
</label> </label>
@@ -119,7 +124,7 @@ const LogbookDrawer = ({ onOpenClose }: LogbookDrawerProps) => {
{logbookContext.state.formMode !== FormMode.ADD && {logbookContext.state.formMode !== FormMode.ADD &&
<> <>
<label className='tab'> <label className='tab'>
<input type='radio' name='my_tabs'/> <input aria-label='tracks' type='radio' name='logbook_drawer_tabs' onChange={onTabClicked} checked={activeTab === 'tracks' ? true : false} />
<FontAwesomeIcon className='mr-1' icon={faMapLocationDot} /> <FontAwesomeIcon className='mr-1' icon={faMapLocationDot} />
Tracks Tracks
</label> </label>

View File

@@ -1,26 +1,26 @@
import { Card, CardActions, CardBody, CardHeader} from "@noahspan/noahspan-components" // import { Card, CardActions, CardBody, CardHeader} from "@noahspan/noahspan-components"
import { PilotCardProps } from "./PilotCardProps.interface" // import { PilotCardProps } from "./PilotCardProps.interface"
import ActionMenu from "../actionMenu/ActionMenu" // import ActionMenu from "../actionMenu/ActionMenu"
const PilotCard = ({ pilots, onDelete, onOpenCloseForm }: PilotCardProps) => { // const PilotCard = ({ pilots, onDelete, onOpenCloseForm }: PilotCardProps) => {
return ( // return (
<div> // <div>
{pilots.map((pilot) => { // {pilots.map((pilot) => {
return ( // return (
<div> // <div>
<Card key={pilot.id}> // <Card key={pilot.id}>
<CardBody> // <CardBody>
<CardHeader>{pilot.name}</CardHeader> // <CardHeader>{pilot.name}</CardHeader>
<CardActions> // <CardActions>
<ActionMenu id={pilot.id} onDelete={onDelete} onOpenCloseForm={onOpenCloseForm} /> // <ActionMenu id={pilot.id} onDelete={onDelete} onOpenCloseForm={onOpenCloseForm} />
</CardActions> // </CardActions>
</CardBody> // </CardBody>
</Card> // </Card>
</div> // </div>
) // )
})} // })}
</div> // </div>
) // )
} // }
export default PilotCard; // export default PilotCard;

View File

@@ -4,9 +4,9 @@ import { IPilotFormProps } from './IPilotFormProps';
import { AxiosError, AxiosResponse } from 'axios'; import { AxiosError, AxiosResponse } from 'axios';
import { FormMode } from '../../enums/formMode'; import { FormMode } from '../../enums/formMode';
import { Person } from '@microsoft/microsoft-graph-types'; import { Person } from '@microsoft/microsoft-graph-types';
import PilotFormCertificates from '../pilotFormCertificates/PilotFormCertificates'; // import PilotFormCertificates from '../pilotFormCertificates/PilotFormCertificates';
import PilotFormEndorsements from '../pilotFormEndorsements/PilotFormEndorsements'; // import PilotFormEndorsements from '../pilotFormEndorsements/PilotFormEndorsements';
import PilotFormMedical from '../pilotFormMedical/PilotFormMedical'; // import PilotFormMedical from '../pilotFormMedical/PilotFormMedical';
import { useOidc } from '../../auth/oidcConfig'; import { useOidc } from '../../auth/oidcConfig';
import httpClient from '../../httpClient/httpClient'; import httpClient from '../../httpClient/httpClient';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
@@ -104,18 +104,7 @@ const PilotForm: React.FC<IPilotFormProps> = ({
}, [pilotId]); }, [pilotId]);
return ( return (
<div className='drawer drawer-end' <div className='drawer drawer-end'>
// closeButton={
// <Button isIconOnly>
// <FontAwesomeIcon icon={faXmark} />
// </Button>
// }
// isOpen={isDrawerOpen}
// placement='right'
// data-testid="pilot-drawer"
// onClose={onCancel}
// size='xl'
>
<input type='checkbox' className='drawer-toggle' onChange={() => {}} checked={isDrawerOpen} /> <input type='checkbox' className='drawer-toggle' onChange={() => {}} checked={isDrawerOpen} />
<div className='drawer-side'> <div className='drawer-side'>
<label <label
@@ -126,10 +115,17 @@ const PilotForm: React.FC<IPilotFormProps> = ({
<div className='menu bg-base-100 text-base-content min-h-full p-4' style={{ width: '25%' }}> <div className='menu bg-base-100 text-base-content min-h-full p-4' style={{ width: '25%' }}>
<FormProvider {...methods}> <FormProvider {...methods}>
<form className='prose max-w-none' onSubmit={methods.handleSubmit(onSubmit)} style={{ paddingBottom: '50px' }}> <form className='prose max-w-none' onSubmit={methods.handleSubmit(onSubmit)} style={{ paddingBottom: '50px' }}>
<h2>
{`${mode.toString().toLowerCase().charAt(0).toUpperCase() + mode.toString().slice(1).toLowerCase()} Pilot`}
</h2>
<div className='grid grid-cols-12 gap-3'> <div className='grid grid-cols-12 gap-3'>
<div className="col-span-10">
<h2 className="mt-0 mb-0 self-center">
{`${mode.toString().toLowerCase().charAt(0).toUpperCase() + mode.toString().slice(1).toLowerCase()} Pilot`}
</h2>
</div>
<div className="col-span-2 justify-self-end self-center">
<button className="btn btn-ghost" onClick={onCancel}>
<FontAwesomeIcon icon={faXmark} />
</button>
</div>
<div className='col-span-3 self-center'> <div className='col-span-3 self-center'>
<span>Name *</span> <span>Name *</span>
</div> </div>

View File

@@ -1,153 +1,153 @@
import { PilotFormCertificatesProps } from './PilotFormCertificatesProps.interface'; // import { PilotFormCertificatesProps } from './PilotFormCertificatesProps.interface';
import { // import {
Button, // Button,
DatePicker, // DatePicker,
Icon, // Icon,
IconButton, // IconButton,
IconName, // IconName,
Input, // Input,
Select // Select
} from '@noahspan/noahspan-components'; // } from '@noahspan/noahspan-components';
import { Controller, useFieldArray, useFormContext } from 'react-hook-form'; // import { Controller, useFieldArray, useFormContext } from 'react-hook-form';
import { FormMode } from '../../enums/formMode'; // import { FormMode } from '../../enums/formMode';
const PilotFormCertificates = ({ // const PilotFormCertificates = ({
isDisabled, // isDisabled,
mode // mode
}: PilotFormCertificatesProps ) => { // }: PilotFormCertificatesProps ) => {
const { // const {
control, // control,
formState: { errors }, // formState: { errors },
} = useFormContext(); // } = useFormContext();
const { fields, append, remove } = useFieldArray({ // const { fields, append, remove } = useFieldArray({
name: 'certificates', // name: 'certificates',
control // control
}); // });
return ( // return (
<div> // <div>
{fields.length > 0 || mode !== FormMode.VIEW && // {fields.length > 0 || mode !== FormMode.VIEW &&
<div> // <div>
<h5>Certificates</h5> // <h5>Certificates</h5>
</div> // </div>
} // }
{fields.length > 0 && ( // {fields.length > 0 && (
<> // <>
<div> // <div>
<h6>Type</h6> // <h6>Type</h6>
</div> // </div>
<div> // <div>
<h6>Number</h6> // <h6>Number</h6>
</div> // </div>
<div> // <div>
<h6>Date of Issue</h6> // <h6>Date of Issue</h6>
</div> // </div>
<div> // <div>
</div> // </div>
{fields.map((field, index) => { // {fields.map((field, index) => {
return ( // return (
<> // <>
<div> // <div>
<Controller // <Controller
name={`certificates.${index}.type`} // name={`certificates.${index}.type`}
control={control} // control={control}
render={({ field: { onChange, value } }) => { // render={({ field: { onChange, value } }) => {
return ( // return (
<Select // <Select
disabled={isDisabled} // disabled={isDisabled}
onChange={onChange} // onChange={onChange}
options={ // options={
[ // [
{ // {
label: 'Student', // label: 'Student',
value: 'student' // value: 'student'
}, // },
{ // {
label: 'Private', // label: 'Private',
value: 'private' // value: 'private'
}, // },
{ // {
label: 'Instrument', // label: 'Instrument',
value: 'instrument' // value: 'instrument'
}, // },
{ // {
label: 'Recreational', // label: 'Recreational',
value: 'recreational' // value: 'recreational'
}, // },
{ // {
label: 'Sport', // label: 'Sport',
value: 'sport' // value: 'sport'
} // }
] // ]
} // }
value={value} // value={value}
/> // />
); // );
}} // }}
/> // />
</div> // </div>
<div> // <div>
<Controller // <Controller
name={`certificates.${index}.number`} // name={`certificates.${index}.number`}
control={control} // control={control}
render={({ field: { onChange, value } }) => { // render={({ field: { onChange, value } }) => {
return ( // return (
<Input // <Input
disabled={isDisabled} // disabled={isDisabled}
onChange={onChange} // onChange={onChange}
value={value} // value={value}
/> // />
) // )
}} // }}
/> // />
</div> // </div>
<div> // <div>
<Controller // <Controller
name={`certificates.${index}.dateOfIssue`} // name={`certificates.${index}.dateOfIssue`}
control={control} // control={control}
render={({ field: { onChange, value } }) => { // render={({ field: { onChange, value } }) => {
return ( // return (
<DatePicker // <DatePicker
disabled={isDisabled} // disabled={isDisabled}
onChange={onChange} // onChange={onChange}
value={value} // value={value}
/> // />
); // );
}} // }}
/> // />
</div> // </div>
<div> // <div>
<IconButton // <IconButton
disabled={isDisabled} // disabled={isDisabled}
onClick={() => remove(index)} // onClick={() => remove(index)}
> // >
<Icon iconName={IconName.TRASH} size='sm' /> // <Icon iconName={IconName.TRASH} size='sm' />
</IconButton> // </IconButton>
</div> // </div>
</> // </>
); // );
})} // })}
</> // </>
)} // )}
{!isDisabled && // {!isDisabled &&
<div> // <div>
<Button // <Button
onClick={() => { // onClick={() => {
append({ // append({
type: '', // type: '',
number: '', // number: '',
dateOfIssue: null // dateOfIssue: null
}); // });
}} // }}
startContent={<Icon iconName={IconName.PLUS} />} // startContent={<Icon iconName={IconName.PLUS} />}
> // >
Add Certificate // Add Certificate
</Button> // </Button>
</div> // </div>
} // }
</div> // </div>
); // );
}; // };
export default PilotFormCertificates; // export default PilotFormCertificates;

View File

@@ -1,129 +1,129 @@
import { PilotFormEndorsementsProps } from './PilotFormEndorsementsProps.interface'; // import { PilotFormEndorsementsProps } from './PilotFormEndorsementsProps.interface';
import { // import {
Button, // Button,
DatePicker, // DatePicker,
Icon, // Icon,
IconButton, // IconButton,
IconName, // IconName,
Select // Select
} from '@noahspan/noahspan-components'; // } from '@noahspan/noahspan-components';
import { Controller, useFieldArray, useFormContext } from 'react-hook-form'; // import { Controller, useFieldArray, useFormContext } from 'react-hook-form';
import { FormMode } from '../../enums/formMode'; // import { FormMode } from '../../enums/formMode';
const PilotFormEndorsements = ({ // const PilotFormEndorsements = ({
mode, // mode,
isDisabled // isDisabled
}: PilotFormEndorsementsProps) => { // }: PilotFormEndorsementsProps) => {
const { // const {
control, // control,
formState: { errors }, // formState: { errors },
setValue // setValue
} = useFormContext(); // } = useFormContext();
const { fields, append, remove } = useFieldArray({ // const { fields, append, remove } = useFieldArray({
name: 'endorsements', // name: 'endorsements',
control // control
}); // });
return ( // return (
<div> // <div>
{fields.length > 0 || mode !== FormMode.VIEW && // {fields.length > 0 || mode !== FormMode.VIEW &&
<div> // <div>
<h5>Endorsements</h5> // <h5>Endorsements</h5>
</div> // </div>
} // }
{fields.length > 0 && ( // {fields.length > 0 && (
<> // <>
<div> // <div>
<h6>Type</h6> // <h6>Type</h6>
</div> // </div>
<div> // <div>
<h6>Date of Issue</h6> // <h6>Date of Issue</h6>
</div> // </div>
<div></div> // <div></div>
{fields.map((field, index) => { // {fields.map((field, index) => {
return ( // return (
<> // <>
<div> // <div>
<Controller // <Controller
name={`endorsements.${index}.type`} // name={`endorsements.${index}.type`}
control={control} // control={control}
render={({ field: { onChange, value } }) => { // render={({ field: { onChange, value } }) => {
return ( // return (
<Select // <Select
disabled={isDisabled} // disabled={isDisabled}
onChange={onChange} // onChange={onChange}
options={ // options={
[ // [
{ // {
label: 'Complex', // label: 'Complex',
value: 'complex' // value: 'complex'
}, // },
{ // {
label: 'High Performance', // label: 'High Performance',
value: 'highPerfomance' // value: 'highPerfomance'
}, // },
{ // {
label: 'High Altitude', // label: 'High Altitude',
value: 'highAltitude' // value: 'highAltitude'
}, // },
{ // {
label: 'Tailwheel', // label: 'Tailwheel',
value: 'tailwheel' // value: 'tailwheel'
} // }
] // ]
} // }
value={value ? value : ''} // value={value ? value : ''}
/> // />
); // );
}} // }}
/> // />
</div> // </div>
<div> // <div>
<Controller // <Controller
name={`endorsements.${index}.dateOfIssue`} // name={`endorsements.${index}.dateOfIssue`}
control={control} // control={control}
render={({ field: { onChange, value } }) => { // render={({ field: { onChange, value } }) => {
return ( // return (
<DatePicker // <DatePicker
disabled={isDisabled} // disabled={isDisabled}
onChange={onChange} // onChange={onChange}
value={value} // value={value}
/> // />
); // );
}} // }}
/> // />
</div> // </div>
<div> // <div>
<IconButton // <IconButton
disabled={isDisabled} // disabled={isDisabled}
onClick={() => remove(index)} // onClick={() => remove(index)}
> // >
<Icon iconName={IconName.TRASH} size="sm" /> // <Icon iconName={IconName.TRASH} size="sm" />
</IconButton> // </IconButton>
</div> // </div>
</> // </>
); // );
})} // })}
</> // </>
)} // )}
{!isDisabled && // {!isDisabled &&
<div> // <div>
<Button // <Button
onClick={() => { // onClick={() => {
append({ // append({
type: '', // type: '',
dateOfIssue: null // dateOfIssue: null
}); // });
}} // }}
startContent={<Icon iconName={IconName.PLUS} />} // startContent={<Icon iconName={IconName.PLUS} />}
> // >
Add Endorsement // Add Endorsement
</Button> // </Button>
</div> // </div>
} // }
</div> // </div>
); // );
}; // };
export default PilotFormEndorsements; // export default PilotFormEndorsements;

View File

@@ -1,77 +1,77 @@
import { DatePicker, Select } from '@noahspan/noahspan-components'; // import { DatePicker, Select } from '@noahspan/noahspan-components';
import { Controller, useFormContext } from "react-hook-form" // import { Controller, useFormContext } from "react-hook-form"
import { PilotFormMedicalProps } from "./PilotFormMedicalProps.interface"; // import { PilotFormMedicalProps } from "./PilotFormMedicalProps.interface";
const PilotFormMedical = ({ isDisabled }: PilotFormMedicalProps) => { // const PilotFormMedical = ({ isDisabled }: PilotFormMedicalProps) => {
const { // const {
control, // control,
formState: { errors }, // formState: { errors },
setValue // setValue
} = useFormContext(); // } = useFormContext();
return ( // return (
<div> // <div>
<div> // <div>
<h5>Medical</h5> // <h5>Medical</h5>
</div> // </div>
<div> // <div>
<h6>Class</h6> // <h6>Class</h6>
</div> // </div>
<div> // <div>
<Controller // <Controller
name="medicalClass" // name="medicalClass"
control={control} // control={control}
render={({ field: { onChange, value } }) => { // render={({ field: { onChange, value } }) => {
return ( // return (
<Select // <Select
disabled={isDisabled} // disabled={isDisabled}
onChange={onChange} // onChange={onChange}
options={ // options={
[ // [
{ // {
label: 'First', // label: 'First',
value: 'first' // value: 'first'
}, // },
{ // {
label: 'Second', // label: 'Second',
value: 'second' // value: 'second'
}, // },
{ // {
label: 'Third', // label: 'Third',
value: 'third' // value: 'third'
}, // },
{ // {
label: 'Basic Med', // label: 'Basic Med',
value: 'basicMed' // value: 'basicMed'
} // }
] // ]
} // }
value={value ? value : ''} // value={value ? value : ''}
/> // />
); // );
}} // }}
/> // />
</div> // </div>
<div> // <div>
<h6>Expiration</h6> // <h6>Expiration</h6>
</div> // </div>
<div> // <div>
<Controller // <Controller
name="medicalExpiration" // name="medicalExpiration"
control={control} // control={control}
render={({ field: { onChange, value } }) => { // render={({ field: { onChange, value } }) => {
return ( // return (
<DatePicker // <DatePicker
disabled={isDisabled} // disabled={isDisabled}
onChange={onChange} // onChange={onChange}
value={value} // value={value}
/> // />
); // );
}} // }}
/> // />
</div> // </div>
</div> // </div>
) // )
} // }
export default PilotFormMedical // export default PilotFormMedical

View File

@@ -4,7 +4,7 @@ import { AxiosError, AxiosResponse } from 'axios';
import { FormMode } from '../../enums/formMode'; import { FormMode } from '../../enums/formMode';
import { initialState, reducer } from './reducer'; import { initialState, reducer } from './reducer';
import ConfirmationDialog from '../confirmationDialog/ConfirmationDialog'; import ConfirmationDialog from '../confirmationDialog/ConfirmationDialog';
import PilotCard from '../pilotCard/PilotCard'; // import PilotCard from '../pilotCard/PilotCard';
import { useUserRole } from '../../hooks/userRole/UseUserRole'; import { useUserRole } from '../../hooks/userRole/UseUserRole';
import { UserRole } from '../../enums/userRole'; import { UserRole } from '../../enums/userRole';
import httpClient from '../../httpClient/httpClient' import httpClient from '../../httpClient/httpClient'
@@ -177,7 +177,7 @@ const Pilots: React.FC<unknown> = () => {
<h1>Pilots</h1> <h1>Pilots</h1>
</div> </div>
<div className='col-span-2 justify-self-end self-center'> <div className='col-span-2 justify-self-end self-center'>
{userRole === UserRole.WRITE && {!state.isLoading && userRole === UserRole.WRITE &&
<button <button
className='btn btn-primary' className='btn btn-primary'
onClick={() => onOpenClosePilotForm(FormMode.ADD)} onClick={() => onOpenClosePilotForm(FormMode.ADD)}
@@ -201,8 +201,8 @@ const Pilots: React.FC<unknown> = () => {
</Alert> </Alert>
</div> </div>
)} )}
<div className='col-span-12 bg-base-100 p-5 border border-base-100 rounded-lg'> {state.pilots.length > 0 && screenSize !== ScreenSize.SM &&
{state.pilots.length > 0 && screenSize !== ScreenSize.SM && <div className='col-span-12 bg-base-100 p-5 border border-base-100 rounded-lg'>
<table className='table min-w-full h-auto table-auto w-full'> <table className='table min-w-full h-auto table-auto w-full'>
<thead className='[&>tr]:first:rounded-lg bg-base-200'> <thead className='[&>tr]:first:rounded-lg bg-base-200'>
{table.getHeaderGroups().map((headerGroup) => ( {table.getHeaderGroups().map((headerGroup) => (
@@ -257,11 +257,11 @@ const Pilots: React.FC<unknown> = () => {
</> </>
</tbody> </tbody>
</table> </table>
} </div>
{state.pilots.length > 0 && screenSize === ScreenSize.SM && }
<PilotCard pilots={state.pilots} onDelete={onDeletePilot} onOpenCloseForm={onOpenClosePilotForm} /> {/* {state.pilots.length > 0 && screenSize === ScreenSize.SM &&
} <PilotCard pilots={state.pilots} onDelete={onDeletePilot} onOpenCloseForm={onOpenClosePilotForm} />
</div> } */}
</div> </div>
{state.isFormOpen && ( {state.isFormOpen && (
<PilotForm <PilotForm

View File

@@ -122,7 +122,7 @@ const TracksForm = () => {
</> </>
) )
})} })}
{logbookContext.state.formMode === FormMode.ADD && {logbookContext.state.formMode === FormMode.EDIT &&
<div className='col-span-12'> <div className='col-span-12'>
<label <label
className='btn cursor-pointer w-full' className='btn cursor-pointer w-full'

455
package-lock.json generated
View File

@@ -86,7 +86,6 @@
"@fortawesome/fontawesome-svg-core": "^7.1.0", "@fortawesome/fontawesome-svg-core": "^7.1.0",
"@fortawesome/free-solid-svg-icons": "^7.1.0", "@fortawesome/free-solid-svg-icons": "^7.1.0",
"@fortawesome/react-fontawesome": "^3.1.0", "@fortawesome/react-fontawesome": "^3.1.0",
"@noahspan/noahspan-components": "^2.0.0-alpha-14",
"@tailwindcss/typography": "^0.5.19", "@tailwindcss/typography": "^0.5.19",
"@tailwindcss/vite": "^4.1.13", "@tailwindcss/vite": "^4.1.13",
"@tanstack/react-table": "^8.21.3", "@tanstack/react-table": "^8.21.3",
@@ -159,71 +158,6 @@
"react": "^18.0.0 || ^19.0.0" "react": "^18.0.0 || ^19.0.0"
} }
}, },
"client/node_modules/@noahspan/noahspan-components": {
"version": "2.0.0-alpha-14",
"resolved": "https://registry.npmjs.org/@noahspan/noahspan-components/-/noahspan-components-2.0.0-alpha-14.tgz",
"integrity": "sha512-PlIQa3Np9pOaHFbLe0bIQTIe1jYVEWOTiSYAS3VXhO1MZ7NGlSu8vgBJQ9ireD8NueE+FlYi56n9cNgeDNY6IA==",
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^6.5.2",
"@fortawesome/free-brands-svg-icons": "^6.5.2",
"@fortawesome/free-regular-svg-icons": "^6.5.2",
"@fortawesome/free-solid-svg-icons": "^6.5.2",
"@fortawesome/react-fontawesome": "^0.2.0",
"@microsoft/microsoft-graph-types": "^2.40.0",
"@tanstack/react-table": "^8.17.3",
"react-daisyui-timetools": "^2.0.2",
"react-day-picker": "^9.9.0"
},
"engines": {
"node": ">=20.0.0"
},
"peerDependencies": {
"react": "^19.x",
"react-dom": "^19.x"
}
},
"client/node_modules/@noahspan/noahspan-components/node_modules/@fortawesome/fontawesome-common-types": {
"version": "6.7.2",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.7.2.tgz",
"integrity": "sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==",
"engines": {
"node": ">=6"
}
},
"client/node_modules/@noahspan/noahspan-components/node_modules/@fortawesome/fontawesome-svg-core": {
"version": "6.7.2",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.2.tgz",
"integrity": "sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA==",
"dependencies": {
"@fortawesome/fontawesome-common-types": "6.7.2"
},
"engines": {
"node": ">=6"
}
},
"client/node_modules/@noahspan/noahspan-components/node_modules/@fortawesome/free-solid-svg-icons": {
"version": "6.7.2",
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.7.2.tgz",
"integrity": "sha512-GsBrnOzU8uj0LECDfD5zomZJIjrPhIlWU82AHwa2s40FKH+kcxQaBvBo3Z4TxyZHIyX8XTDxsyA33/Vx9eFuQA==",
"dependencies": {
"@fortawesome/fontawesome-common-types": "6.7.2"
},
"engines": {
"node": ">=6"
}
},
"client/node_modules/@noahspan/noahspan-components/node_modules/@fortawesome/react-fontawesome": {
"version": "0.2.6",
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.6.tgz",
"integrity": "sha512-mtBFIi1UsYQo7rYonYFkjgYKGoL8T+fEH6NGUpvuqtY3ytMsAoDaPo5rk25KuMtKDipY4bGYM/CkmCHA1N3FUg==",
"dependencies": {
"prop-types": "^15.8.1"
},
"peerDependencies": {
"@fortawesome/fontawesome-svg-core": "~1 || ~6 || ~7",
"react": "^16.3 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"client/node_modules/react": { "client/node_modules/react": {
"version": "19.1.1", "version": "19.1.1",
"resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz",
@@ -232,20 +166,6 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"client/node_modules/react-daisyui-timetools": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/react-daisyui-timetools/-/react-daisyui-timetools-2.0.2.tgz",
"integrity": "sha512-ruNo9eUdNm/tlkgo+zd7qZbDgxTObRAH4CW8KBpxpWDTrS0krYuWcFcao9i4wwYeVfPnWrtgw5AsH895EmKgFA==",
"peerDependencies": {
"@tailwindcss/postcss": "^4.0.12",
"daisyui": "^5",
"dayjs": "^1.11.13",
"postcss": "^8.5.3",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"tailwindcss": "^4.0.12"
}
},
"client/node_modules/react-dom": { "client/node_modules/react-dom": {
"version": "19.1.1", "version": "19.1.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz",
@@ -257,18 +177,6 @@
"react": "^19.1.1" "react": "^19.1.1"
} }
}, },
"node_modules/@alloc/quick-lru": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
"integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
"peer": true,
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/@ampproject/remapping": { "node_modules/@ampproject/remapping": {
"version": "2.3.0", "version": "2.3.0",
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
@@ -2317,11 +2225,6 @@
"google-protobuf": "^3.21.2" "google-protobuf": "^3.21.2"
} }
}, },
"node_modules/@date-fns/tz": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/@date-fns/tz/-/tz-1.4.1.tgz",
"integrity": "sha512-P5LUNhtbj6YfI3iJjw5EL9eUAG6OitD0W3fWQcpQjDRc/QIsL0tRNuO1PcDvPccWL1fSTXXdE1ds+l95DV/OFA=="
},
"node_modules/@esbuild/aix-ppc64": { "node_modules/@esbuild/aix-ppc64": {
"version": "0.21.5", "version": "0.21.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
@@ -2424,36 +2327,6 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0" "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
} }
}, },
"node_modules/@fortawesome/fontawesome-common-types": {
"version": "6.7.2",
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.7.2.tgz",
"integrity": "sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==",
"engines": {
"node": ">=6"
}
},
"node_modules/@fortawesome/free-brands-svg-icons": {
"version": "6.7.2",
"resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.7.2.tgz",
"integrity": "sha512-zu0evbcRTgjKfrr77/2XX+bU+kuGfjm0LbajJHVIgBWNIDzrhpRxiCPNT8DW5AdmSsq7Mcf9D1bH0aSeSUSM+Q==",
"dependencies": {
"@fortawesome/fontawesome-common-types": "6.7.2"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@fortawesome/free-regular-svg-icons": {
"version": "6.7.2",
"resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.7.2.tgz",
"integrity": "sha512-7Z/ur0gvCMW8G93dXIQOkQqHo2M5HLhYrRVC0//fakJXxcF1VmMPsxnG6Ee8qEylA8b8Q3peQXWMNZ62lYF28g==",
"dependencies": {
"@fortawesome/fontawesome-common-types": "6.7.2"
},
"engines": {
"node": ">=6"
}
},
"node_modules/@grpc/grpc-js": { "node_modules/@grpc/grpc-js": {
"version": "1.13.4", "version": "1.13.4",
"resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.13.4.tgz", "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.13.4.tgz",
@@ -3270,6 +3143,7 @@
"version": "2.40.0", "version": "2.40.0",
"resolved": "https://registry.npmjs.org/@microsoft/microsoft-graph-types/-/microsoft-graph-types-2.40.0.tgz", "resolved": "https://registry.npmjs.org/@microsoft/microsoft-graph-types/-/microsoft-graph-types-2.40.0.tgz",
"integrity": "sha512-1fcPVrB/NkbNcGNfCy+Cgnvwxt6/sbIEEFgZHFBJ670zYLegENYJF8qMo7x3LqBjWX2/Eneq5BVVRCLTmlJN+g==", "integrity": "sha512-1fcPVrB/NkbNcGNfCy+Cgnvwxt6/sbIEEFgZHFBJ670zYLegENYJF8qMo7x3LqBjWX2/Eneq5BVVRCLTmlJN+g==",
"dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@nestjs/axios": { "node_modules/@nestjs/axios": {
@@ -5104,282 +4978,6 @@
"node": ">= 10" "node": ">= 10"
} }
}, },
"node_modules/@tailwindcss/postcss": {
"version": "4.1.14",
"resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.14.tgz",
"integrity": "sha512-BdMjIxy7HUNThK87C7BC8I1rE8BVUsfNQSI5siQ4JK3iIa3w0XyVvVL9SXLWO//CtYTcp1v7zci0fYwJOjB+Zg==",
"peer": true,
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
"@tailwindcss/node": "4.1.14",
"@tailwindcss/oxide": "4.1.14",
"postcss": "^8.4.41",
"tailwindcss": "4.1.14"
}
},
"node_modules/@tailwindcss/postcss/node_modules/@tailwindcss/node": {
"version": "4.1.14",
"resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.14.tgz",
"integrity": "sha512-hpz+8vFk3Ic2xssIA3e01R6jkmsAhvkQdXlEbRTk6S10xDAtiQiM3FyvZVGsucefq764euO/b8WUW9ysLdThHw==",
"peer": true,
"dependencies": {
"@jridgewell/remapping": "^2.3.4",
"enhanced-resolve": "^5.18.3",
"jiti": "^2.6.0",
"lightningcss": "1.30.1",
"magic-string": "^0.30.19",
"source-map-js": "^1.2.1",
"tailwindcss": "4.1.14"
}
},
"node_modules/@tailwindcss/postcss/node_modules/@tailwindcss/oxide": {
"version": "4.1.14",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.14.tgz",
"integrity": "sha512-23yx+VUbBwCg2x5XWdB8+1lkPajzLmALEfMb51zZUBYaYVPDQvBSD/WYDqiVyBIo2BZFa3yw1Rpy3G2Jp+K0dw==",
"hasInstallScript": true,
"peer": true,
"dependencies": {
"detect-libc": "^2.0.4",
"tar": "^7.5.1"
},
"engines": {
"node": ">= 10"
},
"optionalDependencies": {
"@tailwindcss/oxide-android-arm64": "4.1.14",
"@tailwindcss/oxide-darwin-arm64": "4.1.14",
"@tailwindcss/oxide-darwin-x64": "4.1.14",
"@tailwindcss/oxide-freebsd-x64": "4.1.14",
"@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.14",
"@tailwindcss/oxide-linux-arm64-gnu": "4.1.14",
"@tailwindcss/oxide-linux-arm64-musl": "4.1.14",
"@tailwindcss/oxide-linux-x64-gnu": "4.1.14",
"@tailwindcss/oxide-linux-x64-musl": "4.1.14",
"@tailwindcss/oxide-wasm32-wasi": "4.1.14",
"@tailwindcss/oxide-win32-arm64-msvc": "4.1.14",
"@tailwindcss/oxide-win32-x64-msvc": "4.1.14"
}
},
"node_modules/@tailwindcss/postcss/node_modules/@tailwindcss/oxide-android-arm64": {
"version": "4.1.14",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.14.tgz",
"integrity": "sha512-a94ifZrGwMvbdeAxWoSuGcIl6/DOP5cdxagid7xJv6bwFp3oebp7y2ImYsnZBMTwjn5Ev5xESvS3FFYUGgPODQ==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"android"
],
"peer": true,
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/postcss/node_modules/@tailwindcss/oxide-darwin-arm64": {
"version": "4.1.14",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.14.tgz",
"integrity": "sha512-HkFP/CqfSh09xCnrPJA7jud7hij5ahKyWomrC3oiO2U9i0UjP17o9pJbxUN0IJ471GTQQmzwhp0DEcpbp4MZTA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"darwin"
],
"peer": true,
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/postcss/node_modules/@tailwindcss/oxide-darwin-x64": {
"version": "4.1.14",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.14.tgz",
"integrity": "sha512-eVNaWmCgdLf5iv6Qd3s7JI5SEFBFRtfm6W0mphJYXgvnDEAZ5sZzqmI06bK6xo0IErDHdTA5/t7d4eTfWbWOFw==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"darwin"
],
"peer": true,
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/postcss/node_modules/@tailwindcss/oxide-freebsd-x64": {
"version": "4.1.14",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.14.tgz",
"integrity": "sha512-QWLoRXNikEuqtNb0dhQN6wsSVVjX6dmUFzuuiL09ZeXju25dsei2uIPl71y2Ic6QbNBsB4scwBoFnlBfabHkEw==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"freebsd"
],
"peer": true,
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/postcss/node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
"version": "4.1.14",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.14.tgz",
"integrity": "sha512-VB4gjQni9+F0VCASU+L8zSIyjrLLsy03sjcR3bM0V2g4SNamo0FakZFKyUQ96ZVwGK4CaJsc9zd/obQy74o0Fw==",
"cpu": [
"arm"
],
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/postcss/node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
"version": "4.1.14",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.14.tgz",
"integrity": "sha512-qaEy0dIZ6d9vyLnmeg24yzA8XuEAD9WjpM5nIM1sUgQ/Zv7cVkharPDQcmm/t/TvXoKo/0knI3me3AGfdx6w1w==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/postcss/node_modules/@tailwindcss/oxide-linux-arm64-musl": {
"version": "4.1.14",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.14.tgz",
"integrity": "sha512-ISZjT44s59O8xKsPEIesiIydMG/sCXoMBCqsphDm/WcbnuWLxxb+GcvSIIA5NjUw6F8Tex7s5/LM2yDy8RqYBQ==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/postcss/node_modules/@tailwindcss/oxide-linux-x64-gnu": {
"version": "4.1.14",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.14.tgz",
"integrity": "sha512-02c6JhLPJj10L2caH4U0zF8Hji4dOeahmuMl23stk0MU1wfd1OraE7rOloidSF8W5JTHkFdVo/O7uRUJJnUAJg==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/postcss/node_modules/@tailwindcss/oxide-linux-x64-musl": {
"version": "4.1.14",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.14.tgz",
"integrity": "sha512-TNGeLiN1XS66kQhxHG/7wMeQDOoL0S33x9BgmydbrWAb9Qw0KYdd8o1ifx4HOGDWhVmJ+Ul+JQ7lyknQFilO3Q==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"linux"
],
"peer": true,
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/postcss/node_modules/@tailwindcss/oxide-wasm32-wasi": {
"version": "4.1.14",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.14.tgz",
"integrity": "sha512-uZYAsaW/jS/IYkd6EWPJKW/NlPNSkWkBlaeVBi/WsFQNP05/bzkebUL8FH1pdsqx4f2fH/bWFcUABOM9nfiJkQ==",
"bundleDependencies": [
"@napi-rs/wasm-runtime",
"@emnapi/core",
"@emnapi/runtime",
"@tybys/wasm-util",
"@emnapi/wasi-threads",
"tslib"
],
"cpu": [
"wasm32"
],
"optional": true,
"peer": true,
"dependencies": {
"@emnapi/core": "^1.5.0",
"@emnapi/runtime": "^1.5.0",
"@emnapi/wasi-threads": "^1.1.0",
"@napi-rs/wasm-runtime": "^1.0.5",
"@tybys/wasm-util": "^0.10.1",
"tslib": "^2.4.0"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/@tailwindcss/postcss/node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
"version": "4.1.14",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.14.tgz",
"integrity": "sha512-Az0RnnkcvRqsuoLH2Z4n3JfAef0wElgzHD5Aky/e+0tBUxUhIeIqFBTMNQvmMRSP15fWwmvjBxZ3Q8RhsDnxAA==",
"cpu": [
"arm64"
],
"optional": true,
"os": [
"win32"
],
"peer": true,
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/postcss/node_modules/@tailwindcss/oxide-win32-x64-msvc": {
"version": "4.1.14",
"resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.14.tgz",
"integrity": "sha512-ttblVGHgf68kEE4om1n/n44I0yGPkCPbLsqzjvybhpwa6mKKtgFfAzy6btc3HRmuW7nHe0OOrSeNP9sQmmH9XA==",
"cpu": [
"x64"
],
"optional": true,
"os": [
"win32"
],
"peer": true,
"engines": {
"node": ">= 10"
}
},
"node_modules/@tailwindcss/postcss/node_modules/magic-string": {
"version": "0.30.19",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.19.tgz",
"integrity": "sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==",
"peer": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.5"
}
},
"node_modules/@tailwindcss/postcss/node_modules/tailwindcss": {
"version": "4.1.14",
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.14.tgz",
"integrity": "sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA==",
"peer": true
},
"node_modules/@tailwindcss/typography": { "node_modules/@tailwindcss/typography": {
"version": "0.5.19", "version": "0.5.19",
"resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.19.tgz", "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.19.tgz",
@@ -7974,15 +7572,11 @@
"version": "5.5.5", "version": "5.5.5",
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-5.5.5.tgz", "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-5.5.5.tgz",
"integrity": "sha512-ekvI93ZkWIJoCOtDl0D2QMxnWvTejk9V5nWBqRv+7t0xjiBXqAK5U6o6JE2RPvlIC3EqwNyUoIZSdHX9MZK3nw==", "integrity": "sha512-ekvI93ZkWIJoCOtDl0D2QMxnWvTejk9V5nWBqRv+7t0xjiBXqAK5U6o6JE2RPvlIC3EqwNyUoIZSdHX9MZK3nw==",
"dev": true,
"funding": { "funding": {
"url": "https://github.com/saadeghi/daisyui?sponsor=1" "url": "https://github.com/saadeghi/daisyui?sponsor=1"
} }
}, },
"node_modules/date-fns-jalali": {
"version": "4.1.0-0",
"resolved": "https://registry.npmjs.org/date-fns-jalali/-/date-fns-jalali-4.1.0-0.tgz",
"integrity": "sha512-hTIP/z+t+qKwBDcmmsnmjWTduxCg+5KfdqWQvb2X/8C9+knYY6epN/pfxdDuyVlSVeFz0sM5eEfwIUQ70U4ckg=="
},
"node_modules/dayjs": { "node_modules/dayjs": {
"version": "1.11.18", "version": "1.11.18",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.18.tgz", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.18.tgz",
@@ -12362,6 +11956,7 @@
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
"peer": true,
"dependencies": { "dependencies": {
"js-tokens": "^3.0.0 || ^4.0.0" "js-tokens": "^3.0.0 || ^4.0.0"
}, },
@@ -14272,21 +13867,6 @@
"node": ">= 6" "node": ">= 6"
} }
}, },
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"dependencies": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.13.1"
}
},
"node_modules/prop-types/node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"node_modules/property-expr": { "node_modules/property-expr": {
"version": "2.0.6", "version": "2.0.6",
"resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz", "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz",
@@ -14515,35 +14095,6 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/react-day-picker": {
"version": "9.11.1",
"resolved": "https://registry.npmjs.org/react-day-picker/-/react-day-picker-9.11.1.tgz",
"integrity": "sha512-l3ub6o8NlchqIjPKrRFUCkTUEq6KwemQlfv3XZzzwpUeGwmDJ+0u0Upmt38hJyd7D/vn2dQoOoLV/qAp0o3uUw==",
"dependencies": {
"@date-fns/tz": "^1.4.1",
"date-fns": "^4.1.0",
"date-fns-jalali": "^4.1.0-0"
},
"engines": {
"node": ">=18"
},
"funding": {
"type": "individual",
"url": "https://github.com/sponsors/gpbl"
},
"peerDependencies": {
"react": ">=16.8.0"
}
},
"node_modules/react-day-picker/node_modules/date-fns": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz",
"integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/kossnocorp"
}
},
"node_modules/react-dom": { "node_modules/react-dom": {
"version": "18.3.1", "version": "18.3.1",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",