Feature/4 pilots add #20
@@ -1,4 +1,12 @@
|
||||
import { Controller, Get, Headers, Query } from '@nestjs/common';
|
||||
import {
|
||||
Body,
|
||||
Controller,
|
||||
Get,
|
||||
Headers,
|
||||
Post,
|
||||
Query,
|
||||
UnprocessableEntityException
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
AppConfigService,
|
||||
MsGraphService,
|
||||
@@ -8,6 +16,8 @@ import { FeatureFlagValue } from '@azure/app-configuration';
|
||||
import { Public } from '@noahspan/noahspan-modules';
|
||||
import { Person } from '@microsoft/microsoft-graph-types';
|
||||
import { AppService } from './app.service';
|
||||
import { PilotDTO } from './pilot/pilot.dto';
|
||||
import { PilotService } from './pilot/pilot.service';
|
||||
|
||||
@Controller()
|
||||
export class AppController {
|
||||
|
||||
@@ -1,11 +1,18 @@
|
||||
import {
|
||||
EntityDateTime,
|
||||
EntityPartitionKey,
|
||||
EntityRowKey,
|
||||
EntityString
|
||||
} from '@nestjs/azure-database';
|
||||
|
||||
@EntityPartitionKey('pilot')
|
||||
@EntityRowKey('id')
|
||||
export class Profile {
|
||||
partitionKey: string;
|
||||
rowKey: string;
|
||||
firstName: string;
|
||||
lastName: string;
|
||||
address: string;
|
||||
city: string;
|
||||
state: string;
|
||||
postalCode: string;
|
||||
lastFlightReview: Date;
|
||||
@EntityString() firstName: string;
|
||||
@EntityString() lastName: string;
|
||||
@EntityString() address: string;
|
||||
@EntityString() city: string;
|
||||
@EntityString() state: string;
|
||||
@EntityString() postalCode: string;
|
||||
@EntityDateTime() lastFlightReview: Date;
|
||||
}
|
||||
|
||||
@@ -16,13 +16,16 @@
|
||||
"@fortawesome/free-regular-svg-icons": "^6.5.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.5.2",
|
||||
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||
"@noahspan/noahspan-components": "^0.5.1",
|
||||
"@hookform/resolvers": "^3.9.0",
|
||||
"@noahspan/noahspan-components": "^0.5.6",
|
||||
"axios": "^1.7.2",
|
||||
"framer-motion": "^11.1.7",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hook-form": "^7.51.4",
|
||||
"react-router-dom": "^6.23.0"
|
||||
"react-router-dom": "^6.23.0",
|
||||
"yup": "^1.4.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/microsoft-graph-types": "^2.40.0",
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
import { useState } from 'react';
|
||||
import { useForm, Controller, FormProvider } from 'react-hook-form';
|
||||
import {
|
||||
Accordion,
|
||||
AccordionBody,
|
||||
AccordionHeader,
|
||||
Button,
|
||||
ChevronDownIcon,
|
||||
ChevronUpIcon,
|
||||
DatePicker,
|
||||
Drawer,
|
||||
DrawerBody,
|
||||
@@ -24,6 +19,40 @@ import { Person } from '@microsoft/microsoft-graph-types';
|
||||
import { AxiosInstance, AxiosResponse } from 'axios';
|
||||
import { useHttpClient } from '../../hooks/httpClient/UseHttpClient';
|
||||
import { useAccessToken } from '../../hooks/accessToken/UseAcessToken';
|
||||
import { zodResolver } from '@hookform/resolvers/zod';
|
||||
import { z } from 'zod';
|
||||
import { IPilotFormCertificates } from '../pilotFormCertificates/IPilotFormCertificates';
|
||||
import { IPilotFormEndorsements } from '../pilotFormEndorsements/IPilotFormEndorsements';
|
||||
|
||||
interface PilotFormSchema {
|
||||
id: string;
|
||||
name: string;
|
||||
address: string;
|
||||
city: string;
|
||||
state: string;
|
||||
postalCode: string;
|
||||
email: string;
|
||||
phone: string;
|
||||
certificates: IPilotFormCertificates[];
|
||||
endorsements: IPilotFormEndorsements[];
|
||||
medicalClass: string;
|
||||
medicalExpiration: string;
|
||||
}
|
||||
|
||||
const schema = z.object({
|
||||
id: z.string(),
|
||||
name: z.string(),
|
||||
address: z.string(),
|
||||
city: z.string(),
|
||||
state: z.string(),
|
||||
postalCode: z.string(),
|
||||
email: z.string(),
|
||||
phone: z.string(),
|
||||
// certificates: z.array(),
|
||||
// endorsements: z.array(),
|
||||
medicalClass: z.string(),
|
||||
medicalExpiration: z.string()
|
||||
});
|
||||
|
||||
interface PilotFormProps {
|
||||
isDrawerOpen: boolean;
|
||||
@@ -39,9 +68,11 @@ const PilotForm: React.FC<PilotFormProps> = ({
|
||||
const [isPeoplePickerLoading, setIsPeoplePickerLoading] =
|
||||
useState<boolean>(false);
|
||||
const { getAccessToken } = useAccessToken();
|
||||
const methods = useForm();
|
||||
const methods = useForm<PilotFormSchema>({
|
||||
resolver: zodResolver(schema)
|
||||
});
|
||||
|
||||
const onSubmit = (data: unknown) => {
|
||||
const onSubmit = (data: PilotFormSchema) => {
|
||||
console.log(data);
|
||||
};
|
||||
|
||||
@@ -120,6 +151,7 @@ const PilotForm: React.FC<PilotFormProps> = ({
|
||||
control={methods.control}
|
||||
render={({ field }) => (
|
||||
<Input
|
||||
className="!border-t-blue-gray-200 focus:!border-t-gray-900"
|
||||
labelProps={{
|
||||
className: 'before:content-none after:content-none'
|
||||
}}
|
||||
@@ -213,6 +245,27 @@ const PilotForm: React.FC<PilotFormProps> = ({
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-1">
|
||||
<Typography variant="h6">Last Review</Typography>
|
||||
</div>
|
||||
<div className="col-span-3">
|
||||
<Controller
|
||||
name="lastReview"
|
||||
control={methods.control}
|
||||
render={({ field }) => {
|
||||
return (
|
||||
<DatePicker
|
||||
handleDateChanged={(date: string) => {
|
||||
methods.setValue('lastReview', date);
|
||||
}}
|
||||
inputProps={{
|
||||
value: field.value
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-4">
|
||||
<Typography variant="h5">Certificates</Typography>
|
||||
<hr className="my-3" />
|
||||
|
||||
@@ -6,7 +6,8 @@ import {
|
||||
Option,
|
||||
PlusIcon,
|
||||
Select,
|
||||
TrashIcon
|
||||
TrashIcon,
|
||||
Typography
|
||||
} from '@noahspan/noahspan-components';
|
||||
import { Controller, useFieldArray, useFormContext } from 'react-hook-form';
|
||||
|
||||
@@ -26,6 +27,20 @@ const PilotFormCertificates: React.FC<IPilotFormCertificates> = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
{fields.length > 0 && (
|
||||
<>
|
||||
<div className="col-span-1">
|
||||
<Typography variant="h6">Type</Typography>
|
||||
</div>
|
||||
<div className="col-span-1">
|
||||
<Typography variant="h6">Number</Typography>
|
||||
</div>
|
||||
<div className="col-span-1">
|
||||
<Typography variant="h6">Date of Issue</Typography>
|
||||
</div>
|
||||
<div className="col-span-1"></div>
|
||||
</>
|
||||
)}
|
||||
{fields.map((field, index) => {
|
||||
return (
|
||||
<>
|
||||
@@ -87,6 +102,7 @@ const PilotFormCertificates: React.FC<IPilotFormCertificates> = ({
|
||||
<Button
|
||||
className="flex items-center gap-3"
|
||||
onClick={() => remove(index)}
|
||||
variant="outlined"
|
||||
>
|
||||
<TrashIcon size="lg" />
|
||||
Delete
|
||||
|
||||
@@ -6,7 +6,8 @@ import {
|
||||
Option,
|
||||
PlusIcon,
|
||||
Select,
|
||||
TrashIcon
|
||||
TrashIcon,
|
||||
Typography
|
||||
} from '@noahspan/noahspan-components';
|
||||
import { Controller, useFieldArray, useFormContext } from 'react-hook-form';
|
||||
|
||||
@@ -26,6 +27,18 @@ const PilotFormEndorsements: React.FC<IPilotFormEndorsements> = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
{fields.length > 0 && (
|
||||
<>
|
||||
<div className="col-span-1">
|
||||
<Typography variant="h6">Type</Typography>
|
||||
</div>
|
||||
<div className="col-span-1">
|
||||
<Typography variant="h6">Date of Issue</Typography>
|
||||
</div>
|
||||
<div className="col-span-1"></div>
|
||||
<div className="col-span-1"></div>
|
||||
</>
|
||||
)}
|
||||
{fields.map((field, index) => {
|
||||
return (
|
||||
<>
|
||||
@@ -75,6 +88,7 @@ const PilotFormEndorsements: React.FC<IPilotFormEndorsements> = ({
|
||||
<Button
|
||||
className="flex items-center gap-3"
|
||||
onClick={() => remove(index)}
|
||||
variant="outlined"
|
||||
>
|
||||
<TrashIcon size="lg" />
|
||||
Delete
|
||||
|
||||
51
package-lock.json
generated
51
package-lock.json
generated
@@ -74,13 +74,16 @@
|
||||
"@fortawesome/free-regular-svg-icons": "^6.5.2",
|
||||
"@fortawesome/free-solid-svg-icons": "^6.5.2",
|
||||
"@fortawesome/react-fontawesome": "^0.2.2",
|
||||
"@noahspan/noahspan-components": "^0.5.1",
|
||||
"@hookform/resolvers": "^3.9.0",
|
||||
"@noahspan/noahspan-components": "^0.5.6",
|
||||
"axios": "^1.7.2",
|
||||
"framer-motion": "^11.1.7",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-hook-form": "^7.51.4",
|
||||
"react-router-dom": "^6.23.0"
|
||||
"react-router-dom": "^6.23.0",
|
||||
"yup": "^1.4.0",
|
||||
"zod": "^3.23.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/microsoft-graph-types": "^2.40.0",
|
||||
@@ -97,6 +100,28 @@
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"app/node_modules/type-fest": {
|
||||
"version": "2.19.0",
|
||||
"resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
|
||||
"integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
|
||||
"engines": {
|
||||
"node": ">=12.20"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"app/node_modules/yup": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/yup/-/yup-1.4.0.tgz",
|
||||
"integrity": "sha512-wPbgkJRCqIf+OHyiTBQoJiP5PFuAXaWiJK6AmYkzQAh5/c2K9hzSApBZG5wV9KoKSePF7sAxmNSvh/13YHkFDg==",
|
||||
"dependencies": {
|
||||
"property-expr": "^2.0.5",
|
||||
"tiny-case": "^1.0.3",
|
||||
"toposort": "^2.0.2",
|
||||
"type-fest": "^2.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@alloc/quick-lru": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
|
||||
@@ -2276,6 +2301,14 @@
|
||||
"@hapi/hoek": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@hookform/resolvers": {
|
||||
"version": "3.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-3.9.0.tgz",
|
||||
"integrity": "sha512-bU0Gr4EepJ/EQsH/IwEzYLsT/PEj5C0ynLQ4m+GSHS+xKH4TfSelhluTgOaoc4kA5s7eCsQbM4wvZLzELmWzUg==",
|
||||
"peerDependencies": {
|
||||
"react-hook-form": "^7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/config-array": {
|
||||
"version": "0.11.14",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
|
||||
@@ -3385,9 +3418,9 @@
|
||||
"link": true
|
||||
},
|
||||
"node_modules/@noahspan/noahspan-components": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@noahspan/noahspan-components/-/noahspan-components-0.5.1.tgz",
|
||||
"integrity": "sha512-H5up7kF35Vvkq0GJwEVNDu80o4V018BVcptDMOrFEAP7Ph/SngAFBOgMBU8o7Jl9oDR91FCQC0VHbzG8cqjROA==",
|
||||
"version": "0.5.6",
|
||||
"resolved": "https://registry.npmjs.org/@noahspan/noahspan-components/-/noahspan-components-0.5.6.tgz",
|
||||
"integrity": "sha512-6Fahu0AsBQCS82p4hZbUnwIcbPMoQ4riViVbtxuYgjmanhxP/gNKH4gqoYgPqMJxg1pSvqKFWMvr2neTPBM07Q==",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^6.5.2",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.5.2",
|
||||
@@ -13133,6 +13166,14 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "3.23.8",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
|
||||
"integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
},
|
||||
"tests": {
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
|
||||
Reference in New Issue
Block a user