adding daisy ui

This commit is contained in:
2025-12-06 20:32:07 -06:00
parent 85b9c11bf1
commit 9a502df48d
8 changed files with 404 additions and 264 deletions

View File

@@ -69,13 +69,17 @@ const Logbook: React.FC<unknown> = () => {
id: 'route', id: 'route',
header: 'Route of Flight', header: 'Route of Flight',
meta: { meta: {
headerAlign: 'center' className: 'border-l border-base-300',
headerAlign: 'text-center'
}, },
columns: [ columns: [
{ {
id: 'routeFrom', id: 'routeFrom',
accessorKey: 'routeFrom', accessorKey: 'routeFrom',
header: 'From' header: 'From',
meta: {
className: 'border-l border-base-300',
}
}, },
{ {
id: 'routeTo', id: 'routeTo',
@@ -89,8 +93,9 @@ const Logbook: React.FC<unknown> = () => {
accessorKey: 'durationOfFlight', accessorKey: 'durationOfFlight',
header: 'Duration Of Flight', header: 'Duration Of Flight',
meta: { meta: {
align: 'right', align: 'text-right',
headerAlign: 'right' className: 'border-l border-base-300',
headerAlign: 'text-right'
}, },
cell: (info: CellContext<LogbookEntry, unknown>) => cell: (info: CellContext<LogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : '', info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : '',
@@ -99,51 +104,63 @@ const Logbook: React.FC<unknown> = () => {
const notes: ColumnDef<LogbookEntry> = { const notes: ColumnDef<LogbookEntry> = {
id: 'notes', id: 'notes',
accessorKey: 'notes', accessorKey: 'notes',
header: 'Notes' header: 'Notes',
meta: {
className: 'border-l border-base-300',
}
} }
const actions: ColumnDef<LogbookEntry> = { const actions: ColumnDef<LogbookEntry> = {
id: 'actions', id: 'actions',
header: 'Actions', header: 'Actions',
meta: { meta: {
align: 'center', align: 'text-center',
headerAlign: 'center' className: 'border-l border-base-300',
headerAlign: 'text-center'
}, },
cell: (info: CellContext<LogbookEntry, unknown>) => { cell: (info: CellContext<LogbookEntry, unknown>) => {
return ( return (
<Dropdown> <div className='dropdown dropdown-end'>
<DropdownTrigger> <div tabIndex={0} role='button' className='btn btn-ghost'><FontAwesomeIcon icon={faEllipsisVertical} /></div>
<Button isIconOnly variant='light' size='lg'> <ul tabIndex={-1} className="dropdown-content menu bg-base-100 rounded-box z-1 w-52 p-2 shadow-sm border border-base-300">
<FontAwesomeIcon icon={faEllipsisVertical} /> <li><a onClick={() => onOpenCloseDrawer(FormMode.EDIT, info.row.original.id)}><FontAwesomeIcon icon={faPen} />Edit</a></li>
</Button> <li><a onClick={() => onOpenCloseDrawer(FormMode.VIEW, info.row.original.id)}><FontAwesomeIcon icon={faEye} />View</a></li>
</DropdownTrigger> <li><a onClick={() => onDeleteLog(info.row.original.id)}><FontAwesomeIcon icon={faTrash} />View</a></li>
<DropdownMenu> </ul>
<DropdownSection showDivider> </div>
<DropdownItem // <Dropdown>
key='edit' // <DropdownTrigger>
onPress={() => onOpenCloseDrawer(FormMode.EDIT, info.row.original.id)} // <Button isIconOnly variant='light' size='lg'>
startContent={<FontAwesomeIcon icon={faPen} />} // <FontAwesomeIcon icon={faEllipsisVertical} />
> // </Button>
Edit // </DropdownTrigger>
</DropdownItem> // <DropdownMenu>
<DropdownItem // <DropdownSection showDivider>
key='view' // <DropdownItem
onPress={() => onOpenCloseDrawer(FormMode.VIEW, info.row.original.id)} // key='edit'
startContent={<FontAwesomeIcon icon={faEye} />} // onPress={() => onOpenCloseDrawer(FormMode.EDIT, info.row.original.id)}
> // startContent={<FontAwesomeIcon icon={faPen} />}
View // >
</DropdownItem> // Edit
</DropdownSection> // </DropdownItem>
<DropdownSection> // <DropdownItem
<DropdownItem // key='view'
key='Delete' // onPress={() => onOpenCloseDrawer(FormMode.VIEW, info.row.original.id)}
onPress={() => onDeleteLog(info.row.original.id)} // startContent={<FontAwesomeIcon icon={faEye} />}
startContent={<FontAwesomeIcon icon={faTrash} />} // >
> // View
Delete // </DropdownItem>
</DropdownItem> // </DropdownSection>
</DropdownSection> // <DropdownSection>
</DropdownMenu> // <DropdownItem
</Dropdown> // key='Delete'
// onPress={() => onDeleteLog(info.row.original.id)}
// startContent={<FontAwesomeIcon icon={faTrash} />}
// >
// Delete
// </DropdownItem>
// </DropdownSection>
// </DropdownMenu>
// </Dropdown>
) )
} }
} }
@@ -173,8 +190,8 @@ const Logbook: React.FC<unknown> = () => {
accessorKey: 'singleEngineLand', accessorKey: 'singleEngineLand',
header: 'Single Engine Land', header: 'Single Engine Land',
meta: { meta: {
align: 'right', align: 'text-right',
headerAlign: 'right' headerAlign: 'text-right'
}, },
cell: (info: CellContext<LogbookEntry, unknown>) => cell: (info: CellContext<LogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : '', info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : '',
@@ -184,7 +201,8 @@ const Logbook: React.FC<unknown> = () => {
id: 'landings', id: 'landings',
header: 'Landings', header: 'Landings',
meta: { meta: {
headerAlign: 'center' className: 'border-l border-base-300',
headerAlign: 'text-center'
}, },
columns: [ columns: [
{ {
@@ -193,8 +211,9 @@ const Logbook: React.FC<unknown> = () => {
header: 'Day', header: 'Day',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info) : '', footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info) : '',
meta: { meta: {
align: 'right', align: 'text-right',
headerAlign: 'right' className: 'border-l border-base-300',
headerAlign: 'text-right'
} }
}, },
{ {
@@ -203,8 +222,8 @@ const Logbook: React.FC<unknown> = () => {
header: 'Night', header: 'Night',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info) : '', footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info) : '',
meta: { meta: {
align: 'right', align: 'text-right',
headerAlign: 'right' headerAlign: 'text-right'
} }
} }
] ]
@@ -213,7 +232,8 @@ const Logbook: React.FC<unknown> = () => {
id: 'instrument', id: 'instrument',
header: 'Instrument', header: 'Instrument',
meta: { meta: {
headerAlign: 'center' className: 'border-l border-base-300',
headerAlign: 'text-center'
}, },
columns: [ columns: [
{ {
@@ -222,8 +242,9 @@ const Logbook: React.FC<unknown> = () => {
header: 'Actual', header: 'Actual',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '', footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: { meta: {
align: 'right', align: 'text-right',
headerAlign: 'right' className: 'border-l border-base-300',
headerAlign: 'text-right'
}, },
cell: (info: CellContext<LogbookEntry, unknown>) => cell: (info: CellContext<LogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : '', info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : '',
@@ -234,8 +255,8 @@ const Logbook: React.FC<unknown> = () => {
header: 'Simulated', header: 'Simulated',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '', footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: { meta: {
align: 'right', align: 'text-right',
headerAlign: 'right' headerAlign: 'text-right'
}, },
cell: (info: CellContext<LogbookEntry, unknown>) => cell: (info: CellContext<LogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : '' info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : ''
@@ -246,8 +267,8 @@ const Logbook: React.FC<unknown> = () => {
header: 'Approaches', header: 'Approaches',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '', footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: { meta: {
align: 'right', align: 'text-right',
headerAlign: 'right' headerAlign: 'text-right'
} }
}, },
{ {
@@ -256,8 +277,8 @@ const Logbook: React.FC<unknown> = () => {
header: 'Holds', header: 'Holds',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '', footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: { meta: {
align: 'right', align: 'text-right',
headerAlign: 'right' headerAlign: 'text-right'
} }
}, },
{ {
@@ -266,8 +287,8 @@ const Logbook: React.FC<unknown> = () => {
header: 'Nav/Track', header: 'Nav/Track',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '', footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: { meta: {
align: 'right', align: 'text-right',
headerAlign: 'right' headerAlign: 'text-right'
} }
} }
] ]
@@ -276,7 +297,8 @@ const Logbook: React.FC<unknown> = () => {
id: 'experienceTraining', id: 'experienceTraining',
header: 'Type of pilot experience or training', header: 'Type of pilot experience or training',
meta: { meta: {
headerAlign: 'center' className: 'border-l border-base-300',
headerAlign: 'text-center'
}, },
columns: [ columns: [
{ {
@@ -285,8 +307,9 @@ const Logbook: React.FC<unknown> = () => {
header: 'Ground Training Received', header: 'Ground Training Received',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '', footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: { meta: {
align: 'right', align: 'text-right',
headerAlign: 'right' className: 'border-l border-base-300',
headerAlign: 'text-right'
}, },
cell: (info: CellContext<LogbookEntry, unknown>) => cell: (info: CellContext<LogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : '' info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : ''
@@ -297,8 +320,8 @@ const Logbook: React.FC<unknown> = () => {
header: 'Flight Training Received', header: 'Flight Training Received',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '', footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: { meta: {
align: 'right', align: 'text-right',
headerAlign: 'right' headerAlign: 'text-right'
}, },
cell: (info: CellContext<LogbookEntry, unknown>) => cell: (info: CellContext<LogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : '' info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : ''
@@ -309,8 +332,8 @@ const Logbook: React.FC<unknown> = () => {
header: 'Cross Country', header: 'Cross Country',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '', footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: { meta: {
align: 'right', align: 'text-right',
headerAlign: 'right' headerAlign: 'text-right'
}, },
cell: (info: CellContext<LogbookEntry, unknown>) => cell: (info: CellContext<LogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : '' info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : ''
@@ -321,8 +344,8 @@ const Logbook: React.FC<unknown> = () => {
header: 'Night', header: 'Night',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '', footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: { meta: {
align: 'right', align: 'text-right',
headerAlign: 'right' headerAlign: 'text-right'
}, },
cell: (info: CellContext<LogbookEntry, unknown>) => cell: (info: CellContext<LogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : '' info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : ''
@@ -333,8 +356,8 @@ const Logbook: React.FC<unknown> = () => {
header: 'Solo', header: 'Solo',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '', footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: { meta: {
align: 'right', align: 'text-right',
headerAlign: 'right' headerAlign: 'text-right'
}, },
cell: (info: CellContext<LogbookEntry, unknown>) => cell: (info: CellContext<LogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : '' info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : ''
@@ -345,8 +368,8 @@ const Logbook: React.FC<unknown> = () => {
header: 'Pilot In Command', header: 'Pilot In Command',
footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '', footer: (info: HeaderContext<LogbookEntry, unknown>) => columnTotal(info) > 0 ? columnTotal(info).toFixed(1) : '',
meta: { meta: {
align: 'right', align: 'text-right',
headerAlign: 'right' headerAlign: 'text-right'
}, },
cell: (info: CellContext<LogbookEntry, unknown>) => cell: (info: CellContext<LogbookEntry, unknown>) =>
info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : '' info.getValue() ? parseFloat(info.getValue() as string).toFixed(1) : ''
@@ -531,22 +554,22 @@ const Logbook: React.FC<unknown> = () => {
</div> </div>
)} )}
{!state.isLoading && ( {!state.isLoading && (
<div className='col-span-12'> <div className='col-span-12 p-5 bg-base-100 border border-base-100 rounded-lg'>
{state.entries.length > 0 && screenSize !== ScreenSize.SM && ( {state.entries.length > 0 && screenSize !== ScreenSize.SM && (
<div className='p-4 z-0 flex flex-col relative justify-between gap-4 bg-content1 overflow-auto shadow-small rounded-large w-full'> <div className='overflow-x-auto'>
<table className='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'> <thead className='bg-base-200'>
{table.getHeaderGroups().map((headerGroup) => ( {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) => { {headerGroup.headers.map((header, headerIndex) => {
return ( return (
<th <th
className={`${header.column.columnDef.meta?.align ? textAlignment[header.column.columnDef.meta?.align] : ''} 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`} 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} colSpan={header.colSpan}
key={header.id} key={header.id}
> >
{header.isPlaceholder ? null : ( {header.isPlaceholder ? null : (
<div> <div className={`${header.column.columnDef.meta?.headerAlign ? header.column.columnDef.meta?.headerAlign : ''}`}>
{flexRender( {flexRender(
header.column.columnDef.header, header.column.columnDef.header,
header.getContext() header.getContext()
@@ -572,13 +595,15 @@ const Logbook: React.FC<unknown> = () => {
{row.getVisibleCells().map((cell) => { {row.getVisibleCells().map((cell) => {
return ( return (
<td <td
className={`${cell.column.columnDef.meta?.align ? textAlignment[cell.column.columnDef.meta?.align] : ''} 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`} 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} key={cell.id}
> >
<div className={`${cell.column.columnDef.meta?.align ? cell.column.columnDef.meta?.align : ''}`}>
{flexRender( {flexRender(
cell.column.columnDef.cell, cell.column.columnDef.cell,
cell.getContext() cell.getContext()
)} )}
</div>
</td> </td>
); );
})} })}
@@ -587,7 +612,7 @@ const Logbook: React.FC<unknown> = () => {
})} })}
</> </>
</tbody> </tbody>
<thead className='[&>tr]:first:rounded-lg'> <thead className='[&>tr]:first:rounded-lg bg-base-200'>
{table.getFooterGroups().map((footerGroup, index) => { {table.getFooterGroups().map((footerGroup, index) => {
if (index === 0) { if (index === 0) {
return ( return (
@@ -597,14 +622,16 @@ const Logbook: React.FC<unknown> = () => {
<td <td
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' 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'
key={header.id} key={header.id}
align={header.column.columnDef.meta?.align}
> >
<div className={`${header.column.columnDef.meta?.headerAlign ? header.column.columnDef.meta?.headerAlign : ''}`}>
{header.isPlaceholder {header.isPlaceholder
? null ? null
: flexRender( : flexRender(
header.column.columnDef.footer, header.column.columnDef.footer,
header.getContext() header.getContext()
)} )
}
</div>
</td> </td>
); );
})} })}

View File

@@ -48,7 +48,8 @@ const route: ColumnDef<LogbookEntry> = {
id: 'route', id: 'route',
header: 'Route of Flight', header: 'Route of Flight',
meta: { meta: {
headerAlign: 'center' headerAlign: 'center',
className: 'border-l border-base-400'
}, },
columns: [ columns: [
{ {

View File

@@ -1,5 +1,6 @@
import { LogbookCardProps } from "./LogbookCardProps.interface"; import { LogbookCardProps } from "./LogbookCardProps.interface";
import TrackMap from "../trackMap/TrackMap"; import TrackMap from "../trackMap/TrackMap";
import { Button, Collapse, CollapseContent, CollapseTitle } from '@noahspan/noahspan-components'
const LogbookCard = ({ logs, mode, onDelete, onOpenCloseForm }: LogbookCardProps) => { const LogbookCard = ({ logs, mode, onDelete, onOpenCloseForm }: LogbookCardProps) => {
return ( return (
@@ -9,10 +10,10 @@ const LogbookCard = ({ logs, mode, onDelete, onOpenCloseForm }: LogbookCardProps
const formattedDate: string = `${date.getMonth()}/${date.getDate()}/${date.getFullYear()}`; const formattedDate: string = `${date.getMonth()}/${date.getDate()}/${date.getFullYear()}`;
return ( return (
<div> <div className='card bg-base-100 border border-base-300 p-2'>
<div className='card bg-base-100 card-border border-base-300 p-5 z-10' key={log.id}> <div className='card-body' key={log.id}>
<h2 className='card-title font-bold text-2xl'>{formattedDate}</h2> <h2 className='card-title font-bold text-2xl'>{formattedDate}</h2>
<div className='card-body'> <div>
{mode === 'flights' && log.tracks && log.tracks.length > 0 && {mode === 'flights' && log.tracks && log.tracks.length > 0 &&
<div className='mb-5'> <div className='mb-5'>
<TrackMap <TrackMap
@@ -22,7 +23,9 @@ const LogbookCard = ({ logs, mode, onDelete, onOpenCloseForm }: LogbookCardProps
/> />
</div> </div>
} }
<div tabIndex={0} className='collapse collapse-arrow bg-base-100 border-base-300 border z-50'> </div>
<div className='collapse collapse-arrow bg-base-100 border-base-300 border'>
<input type='radio' name='details-accordion' />
<div className='collapse-title font-semibold'>Details</div> <div className='collapse-title font-semibold'>Details</div>
<div className='collapse-content'> <div className='collapse-content'>
<div className='grid grid-cols-12 gap-3 mr-[30%] ml-[30%] mt-4 mb-4'> <div className='grid grid-cols-12 gap-3 mr-[30%] ml-[30%] mt-4 mb-4'>
@@ -65,7 +68,6 @@ const LogbookCard = ({ logs, mode, onDelete, onOpenCloseForm }: LogbookCardProps
</div> </div>
</div> </div>
</div> </div>
</div>
) )
})} })}
</div> </div>

View File

@@ -75,22 +75,28 @@ const LogbookDrawer = ({ onOpenClose }: LogbookDrawerProps) => {
return ( return (
<div className='drawer drawer-end' <div className='drawer drawer-end'
closeButton={ // closeButton={
<Button isIconOnly> // <Button isIconOnly>
<FontAwesomeIcon icon={faXmark} /> // <FontAwesomeIcon icon={faXmark} />
</Button> // </Button>
} // }
isOpen={logbookContext.state.isDrawerOpen} // isOpen={logbookContext.state.isDrawerOpen}
onClose={onCancel} // onClose={onCancel}
> >
<div> <input type='checkbox' className='drawer-toggle' onChange={() => {}} checked={logbookContext.state.isDrawerOpen} />
<div className="drawer-side">
<label
htmlFor='my-drawer-1'
aria-label='close-sidebar'
className='drawer-overlay'
></label>
<div className='menu bg-base-100 text-base-content min-h-full p-4' style={{ width: '50%' }}>
<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' }}>
<DrawerHeader> <h2>
{`${logbookContext.state.formMode.toString().toLowerCase().charAt(0).toUpperCase() + logbookContext.state.formMode.toString().slice(1).toLowerCase()} Entry`} {`${logbookContext.state.formMode.toString().toLowerCase().charAt(0).toUpperCase() + logbookContext.state.formMode.toString().slice(1).toLowerCase()} Entry`}
</DrawerHeader> </h2>
<div className='drawer-side'> {/* {logbookContext.state.formAlert && (
{logbookContext.state.formAlert && (
<div className='col-span-12'> <div className='col-span-12'>
<Alert <Alert
onClose={() => onClose={() =>
@@ -100,15 +106,27 @@ const LogbookDrawer = ({ onOpenClose }: LogbookDrawerProps) => {
title={logbookContext.state.formAlert.message} title={logbookContext.state.formAlert.message}
/> />
</div> </div>
)} )} */}
<Tabs <LogForm />
color='default' {/* <div className='tabs tabs-lift'>
fullWidth={true} <label className='tab'>
onSelectionChange={onSelectedKeyChanged} <input type='radio' name='my_tabs_1' />
selectedKey={activeTab as string} <FontAwesomeIcon icon={faClock} />
variant='solid' Time
> </label>
<Tab <div className="tab-content bg-base-100 border-base-300 p-6">
<LogForm />
</div>
<label className='tab'>
<input type='radio' name='my_tabs_1' />
<FontAwesomeIcon icon={faMapLocationDot} />
Tracks
</label>
<div className="tab-content bg-base-100 border-base-300 p-6">
<TracksForm />
</div> */}
{/* <input type='radio' name='my_tabs_1' className='tab' aria-label='Tracks' /> */}
{/* <input
key='time' key='time'
title={ title={
<div className="flex items-center space-x-2"> <div className="flex items-center space-x-2">
@@ -117,7 +135,7 @@ const LogbookDrawer = ({ onOpenClose }: LogbookDrawerProps) => {
</div> </div>
} }
> >
<LogForm />
</Tab> </Tab>
{logbookContext.state.formMode !== FormMode.ADD && {logbookContext.state.formMode !== FormMode.ADD &&
<Tab <Tab
@@ -131,43 +149,43 @@ const LogbookDrawer = ({ onOpenClose }: LogbookDrawerProps) => {
> >
<TracksForm /> <TracksForm />
</Tab> </Tab>
} } */}
</Tabs> </div>
</DrawerBody>
{activeTab !== 'tracks' && {activeTab !== 'tracks' &&
<DrawerFooter> <div>
<div className='grid grid-cols-12 gap-3'> <div className='grid grid-cols-12 gap-3'>
<div className='col-span-12 justify-self-end self-center'> <div className='col-span-12 justify-self-end self-center'>
<Button <button
className='btn'
disabled={ disabled={
logbookContext.state.isFormDisabled && logbookContext.state.formMode.toString() !== FormMode.VIEW logbookContext.state.isFormDisabled && logbookContext.state.formMode.toString() !== FormMode.VIEW
? logbookContext.state.isFormDisabled ? logbookContext.state.isFormDisabled
: false : false
} }
startContent={<FontAwesomeIcon icon={faXmark} />} onClick={onCancel}
onPress={onCancel}
> >
<FontAwesomeIcon icon={faXmark} />
{logbookContext.state.formMode.toString() !== FormMode.VIEW ? 'Cancel' : 'Close'} {logbookContext.state.formMode.toString() !== FormMode.VIEW ? 'Cancel' : 'Close'}
</Button> </button>
{logbookContext.state.formMode.toString() !== FormMode.VIEW && ( {logbookContext.state.formMode.toString() !== FormMode.VIEW && (
<Button <button
className='ml-[10px]' className='btn btn-primary ml-[10px]'
color='primary'
disabled={logbookContext.state.isFormDisabled} disabled={logbookContext.state.isFormDisabled}
startContent={<FontAwesomeIcon icon={faSave} />}
type="submit" type="submit"
> >
<FontAwesomeIcon icon={faSave} />
Save Save
</Button> </button>
)} )}
</div> </div>
</div> </div>
</DrawerFooter> </div>
} }
</form> </form>
</FormProvider> </FormProvider>
</DrawerContent> </div>
</Drawer> </div>
</div>
) )
} }

View File

@@ -12,7 +12,9 @@ import { ScreenSize } from '../../enums/screenSize';
import { useBreakpoints } from '../../hooks/useBreakpoints/UseBreakpoints'; import { useBreakpoints } from '../../hooks/useBreakpoints/UseBreakpoints';
import { Alert, Button, Dropdown, DropdownItem, DropdownSection, Table, TableHeader, TableBody, TableColumn, TableRow, TableCell, DropdownTrigger, DropdownMenu } from '@heroui/react' import { Alert, Button, Dropdown, DropdownItem, DropdownSection, Table, TableHeader, TableBody, TableColumn, TableRow, TableCell, DropdownTrigger, DropdownMenu } from '@heroui/react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faEllipsisVertical, faPen, faEye, faTrash, faPlus } from '@fortawesome/free-solid-svg-icons' import { faEllipsisVertical, faPen, faEye, faTrash, faPlus } from '@fortawesome/free-solid-svg-icons';
import { CellContext, ColumnDef, flexRender, getCoreRowModel, getPaginationRowModel, HeaderContext, useReactTable } from '@tanstack/react-table';
import { Pilot } from './Pilot.interface';
const Pilots: React.FC<unknown> = () => { const Pilots: React.FC<unknown> = () => {
const [state, dispatch] = useReducer(reducer, initialState); const [state, dispatch] = useReducer(reducer, initialState);
@@ -27,6 +29,8 @@ const Pilots: React.FC<unknown> = () => {
`api/pilots` `api/pilots`
); );
console.log(response)
if (response.data.length > 0) { if (response.data.length > 0) {
dispatch({ type: 'SET_PILOTS', payload: response.data }); dispatch({ type: 'SET_PILOTS', payload: response.data });
@@ -115,14 +119,19 @@ const Pilots: React.FC<unknown> = () => {
}); });
}; };
const columns = [ const columns: ColumnDef<Pilot>[]= [
{ {
id: 'name', id: 'name',
name: 'Name' accessorKey: 'name',
header: 'Name'
}, },
{ {
id: 'actions', id: 'actions',
name: 'Actions' header: 'Actions',
meta: {
align: 'text-center',
headerAlign: 'text-center'
}
} }
] ]
@@ -174,6 +183,19 @@ const Pilots: React.FC<unknown> = () => {
} }
} }
const textAlignment = {
center: 'text-center',
left: 'text-start',
right: 'text-end'
};
const table = useReactTable({
data: state.pilots,
columns: columns,
getCoreRowModel: getCoreRowModel(),
getPaginationRowModel: getPaginationRowModel()
});
useEffect(() => { useEffect(() => {
if (!state.isFormOpen) { if (!state.isFormOpen) {
getPilots(); getPilots();
@@ -188,14 +210,14 @@ const Pilots: 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 <button
color='primary' className='btn btn-primary'
onPress={() => onOpenClosePilotForm(FormMode.ADD)} onClick={() => onOpenClosePilotForm(FormMode.ADD)}
startContent={<FontAwesomeIcon icon={faPlus} />}
data-testid="pilot-add-button" data-testid="pilot-add-button"
> >
<FontAwesomeIcon icon={faPlus} />
Add Pilot Add Pilot
</Button> </button>
} }
</div> </div>
{!state.isLoading && state.alert && ( {!state.isLoading && state.alert && (
@@ -209,31 +231,62 @@ const Pilots: React.FC<unknown> = () => {
/> />
</div> </div>
)} )}
<div className='col-span-12'> <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 &&
<Table> <table className='table min-w-full h-auto table-auto w-full'>
<TableHeader columns={columns}> <thead className='[&>tr]:first:rounded-lg bg-base-200'>
{(column) => ( {table.getHeaderGroups().map((headerGroup) => (
<TableColumn <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}>
key={column.id} {headerGroup.headers.map((header) => {
align={column.id === "actions" ? "center" : "start"} return (
<th
className={`${header.column.columnDef.meta?.headerAlign ? header.column.columnDef.meta?.headerAlign : ''} group/th px-3 h-10 align-middle bg-default-100 whitespace-nowrap text-foreground-500 text-tiny font-semibold rounded 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}
> >
{column.name} {header.isPlaceholder ? null : (
</TableColumn> <div>
{flexRender(
header.column.columnDef.header,
header.getContext()
)} )}
</TableHeader> {/* {header.column.getCanFilter() ? (
<TableBody items={state.pilots}> <div>
{(item) => ( <Filter column={header.column} table={table} />
<TableRow key={item.id}> </div>
{(columnKey => ( ) : null} */}
<TableCell> </div>
{renderCell(item, columnKey)} )}
</TableCell> </th>
);
})}
</tr>
))} ))}
</TableRow> </thead>
<tbody>
<>
{table.getRowModel().rows.map((row) => {
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}>
{row.getVisibleCells().map((cell) => {
return (
<td
className={`${cell.column.columnDef.meta?.align ? cell.column.columnDef.meta?.align : ''} 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}
>
{flexRender(
cell.column.columnDef.cell,
cell.getContext()
)} )}
</TableBody> </td>
</Table> );
})}
</tr>
);
})}
</>
</tbody>
</table>
} }
{state.pilots.length > 0 && screenSize === ScreenSize.SM && {state.pilots.length > 0 && screenSize === ScreenSize.SM &&
<PilotCard pilots={state.pilots} onDelete={onDeletePilot} onOpenCloseForm={onOpenClosePilotForm} /> <PilotCard pilots={state.pilots} onDelete={onDeletePilot} onOpenCloseForm={onOpenClosePilotForm} />

View File

@@ -7,7 +7,7 @@ import { Avatar, Button, Link, Navbar, NavbarBrand, NavbarContent, NavbarItem, D
import httpClient from '../../httpClient/httpClient' import httpClient from '../../httpClient/httpClient'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faPlane, faSignIn, faSignOut } from '@fortawesome/free-solid-svg-icons' import { faPlane, faSignIn, faSignOut } from '@fortawesome/free-solid-svg-icons'
import { useLocation } from 'react-router-dom'; import { NavLink, useLocation } from 'react-router-dom';
const SiteNav = () => { const SiteNav = () => {
const [userPhoto, setUserPhoto] = useState<string>(); const [userPhoto, setUserPhoto] = useState<string>();
@@ -58,8 +58,8 @@ const SiteNav = () => {
try { try {
const userProfile = await getUserProfile(); const userProfile = await getUserProfile();
const userPhoto = await getUserPhoto(); const userPhoto = await getUserPhoto();
console.log(userPhoto)
setUserPhoto(userPhoto); // setUserPhoto(userPhoto);
appContext.dispatch({ appContext.dispatch({
type: 'SET_USER_PROFILE', type: 'SET_USER_PROFILE',
@@ -80,7 +80,7 @@ const SiteNav = () => {
return ( return (
<div className="navbar bg-base-100 shadow-sm w-full"> <div className="navbar bg-base-100 shadow-sm w-full">
<div className="navbar-start"> <div className="navbar-start ml-8">
<div className="dropdown"> <div className="dropdown">
<div tabIndex={0} role="button" className="btn btn-ghost lg:hidden"> <div tabIndex={0} role="button" className="btn btn-ghost lg:hidden">
<svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 6h16M4 12h8m-8 6h16" /> </svg> <svg xmlns="http://www.w3.org/2000/svg" className="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor"> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M4 6h16M4 12h8m-8 6h16" /> </svg>
@@ -99,11 +99,17 @@ const SiteNav = () => {
<li><a>Item 3</a></li> <li><a>Item 3</a></li>
</ul> </ul>
</div> </div>
<a className="btn btn-ghost text-xl">daisyUI</a> <img
height={35}
width={35}
src='noahspan-logo.png'
style={{ marginRight: '5px' }}
/>
<FontAwesomeIcon icon={faPlane} size='2x' />
</div> </div>
<div className="navbar-center hidden lg:flex"> <div className="navbar-center hidden lg:flex">
<ul className="menu menu-horizontal px-1"> <ul className="menu menu-horizontal px-1">
<li><a>Item 1</a></li> {/* <li><a>Item 1</a></li>
<li> <li>
<details> <details>
<summary>Parent</summary> <summary>Parent</summary>
@@ -113,11 +119,42 @@ const SiteNav = () => {
</ul> </ul>
</details> </details>
</li> </li>
<li><a>Item 3</a></li> <li><a>Item 3</a></li> */}
{pages.length > 0 && pages.map((page, index) => {
return (
<li><NavLink to={page.path}>{page.name}</NavLink></li>
)
})}
</ul> </ul>
</div> </div>
<div className="navbar-end"> <div className="navbar-end mr-8">
<a className="btn">Button</a> {!isUserLoggedIn &&
<button className='btn btn-ghost' onClick={() => login()}><FontAwesomeIcon icon={faSignIn} />Sign In</button>
}
{isUserLoggedIn &&
<div className='dropdown dropdown-end'>
<div tabIndex={0} role='button'>
<div className={`avatar ${userPhoto ? userPhoto : 'avatar-placeholder'}`}>
{userPhoto &&
<div className='w-12 rounded-full'>
<img src={userPhoto} />
</div>
}
{!userPhoto &&
<div className='bg-neutral text-neutral-content w-10 rounded-full'>
<span>NS</span>
</div>
}
</div>
</div>
<ul
tabIndex={0}
className='dropdown-content menu bg-base-100 rounded-box z-1 w-52 p-2 shadow-sm border border-base-300'
>
<li><a onClick={() => logout({redirectTo: 'specific url', url: '/'})}><FontAwesomeIcon icon={faSignOut} />Sign Out</a></li>
</ul>
</div>
}
</div> </div>
</div> </div>
// <Navbar isBordered maxWidth='full' position='static'> // <Navbar isBordered maxWidth='full' position='static'>

View File

@@ -1,5 +1,5 @@
@import "tailwindcss"; @import "tailwindcss";
@plugin "@tailwindcss/typography"; @plugin "daisyui";
@plugin "daisyui/theme" { @plugin "daisyui/theme" {
name: "lofi"; name: "lofi";
default: true; default: true;
@@ -34,6 +34,7 @@
--depth: 0; --depth: 0;
--noise: 0; --noise: 0;
} }
@plugin "@tailwindcss/typography";
body { body {
background-color: #f5f5f5; background-color: #f5f5f5;

View File

@@ -3,8 +3,9 @@ import '@tanstack/react-table';
/* eslint-disable */ /* eslint-disable */
declare module '@tanstack/react-table' { declare module '@tanstack/react-table' {
interface ColumnMeta<TData extends RowData, TValue> { interface ColumnMeta<TData extends RowData, TValue> {
align?: 'left' | 'center' | 'right'; align?: 'text-left' | 'text-center' | 'text-right';
headerAlign?: 'left' | 'center' | 'right'; className?: string;
headerAlign?: 'text-left' | 'text-center' | 'text-right';
} }
} }
/* eslint-enable */ /* eslint-enable */