renaming app directory
This commit is contained in:
354
app/src/components/projectForm/ProjectForm.tsx
Normal file
354
app/src/components/projectForm/ProjectForm.tsx
Normal file
@@ -0,0 +1,354 @@
|
||||
import { useEffect, useReducer } from 'react';
|
||||
import {
|
||||
Alert,
|
||||
Button,
|
||||
Drawer,
|
||||
Grid,
|
||||
Icon,
|
||||
IconButton,
|
||||
IconName,
|
||||
TextField,
|
||||
Typography
|
||||
} from '@noahspan/noahspan-components';
|
||||
import { useForm, Controller, FormProvider } from 'react-hook-form';
|
||||
import { initialState, reducer } from './reducer';
|
||||
import { ProjectFormProps } from './ProjectFormProps.interface';
|
||||
import { FormMode } from '../../enums/formMode';
|
||||
import { useIsAuthenticated } from '@azure/msal-react';
|
||||
import { useAccessToken } from '../../hooks/accessToken/UseAccessToken';
|
||||
import { useHttpClient } from '../../hooks/httpClient/UseHttpClient';
|
||||
import { AxiosError, AxiosInstance, AxiosResponse } from 'axios';
|
||||
|
||||
const ProjectForm = ({ isDrawerOpen, mode, onOpenClose, projectId }: ProjectFormProps) => {
|
||||
const [state, dispatch] = useReducer(reducer, initialState);
|
||||
const httpClient: AxiosInstance = useHttpClient();
|
||||
const { getAccessToken } = useAccessToken();
|
||||
const isAuthenticated = useIsAuthenticated();
|
||||
const defaultValues = {
|
||||
partitionKey: 'project',
|
||||
rowKey: '',
|
||||
title: '',
|
||||
subTitle: '',
|
||||
iconName: '',
|
||||
summary: '',
|
||||
repoName: '',
|
||||
siteUrl: '',
|
||||
order: ''
|
||||
}
|
||||
const methods = useForm({
|
||||
defaultValues: defaultValues
|
||||
});
|
||||
const watchRepoName = methods.watch(['repoName'])
|
||||
|
||||
const onCancel = () => {
|
||||
methods.reset(defaultValues);
|
||||
dispatch({ type: 'SET_IS_DISABLED', payload: false });
|
||||
onOpenClose(FormMode.CANCEL);
|
||||
};
|
||||
|
||||
const onSubmit = async (data: unknown) => {
|
||||
console.log(data)
|
||||
try {
|
||||
dispatch({ type: 'SET_IS_LOADING', payload: true });
|
||||
|
||||
const accessToken: string = await getAccessToken();
|
||||
|
||||
if (!projectId) {
|
||||
await httpClient.post(`api/projects`, data, {
|
||||
headers: {
|
||||
Authorization: accessToken
|
||||
}
|
||||
});
|
||||
} else {
|
||||
await httpClient.put(`api/projects/project/${projectId}`, data, {
|
||||
headers: {
|
||||
Authorization: accessToken
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
methods.reset(defaultValues);
|
||||
dispatch({ type: 'SET_IS_DISABLED', payload: false });
|
||||
onOpenClose(FormMode.CANCEL);
|
||||
} catch (error) {
|
||||
const axiosError = error as AxiosError;
|
||||
|
||||
dispatch({ type: 'SET_ERROR', payload: axiosError.message });
|
||||
} finally {
|
||||
dispatch({ type: 'SET_IS_LOADING', payload: false });
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (watchRepoName.length > 0) {
|
||||
methods.setValue('rowKey', watchRepoName[0])
|
||||
}
|
||||
}, [watchRepoName])
|
||||
|
||||
useEffect(() => {
|
||||
if (mode === FormMode.VIEW) {
|
||||
dispatch({ type: 'SET_IS_DISABLED', payload: true });
|
||||
}
|
||||
}, [mode]);
|
||||
|
||||
useEffect(() => {
|
||||
const getProject = async () => {
|
||||
try {
|
||||
dispatch({ type: 'SET_IS_LOADING', payload: true });
|
||||
|
||||
const config = isAuthenticated
|
||||
? { headers: { Authorization: await getAccessToken() } }
|
||||
: {};
|
||||
const response: AxiosResponse = await httpClient.get(
|
||||
`api/projects/project/${projectId}`,
|
||||
config
|
||||
);
|
||||
const entry = response.data;
|
||||
|
||||
methods.reset(entry);
|
||||
} catch (error) {
|
||||
const axiosError = error as AxiosError;
|
||||
|
||||
dispatch({ type: 'SET_ERROR', payload: axiosError.message });
|
||||
} finally {
|
||||
dispatch({ type: 'SET_IS_LOADING', payload: false });
|
||||
}
|
||||
};
|
||||
|
||||
if (projectId && isDrawerOpen) {
|
||||
getProject();
|
||||
}
|
||||
}, [projectId]);
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
open={isDrawerOpen}
|
||||
anchor='right'
|
||||
PaperProps={{
|
||||
sx: {
|
||||
padding: '30px',
|
||||
width: '33%'
|
||||
}
|
||||
}}
|
||||
>
|
||||
<FormProvider {...methods}>
|
||||
<form onSubmit={methods.handleSubmit(onSubmit)}>
|
||||
<Grid container spacing={2}>
|
||||
<Grid size={11}>
|
||||
<Typography variant='h4'>{`${mode.toString().toLowerCase().charAt(0).toUpperCase() + mode.toString().slice(1).toLowerCase()} Project`}</Typography>
|
||||
</Grid>
|
||||
<Grid display="flex" justifyContent="right" size={1}>
|
||||
<IconButton onClick={onCancel}>
|
||||
<Icon iconName={IconName.XMARK} />
|
||||
</IconButton>
|
||||
</Grid>
|
||||
{state.error && (
|
||||
<Grid display="flex" justifyContent="center" size={12}>
|
||||
<Alert
|
||||
onClose={() =>
|
||||
dispatch({ type: 'SET_ERROR', payload: undefined })
|
||||
}
|
||||
severity="error"
|
||||
sx={{ width: '100%' }}
|
||||
>
|
||||
{state.error}
|
||||
</Alert>
|
||||
</Grid>
|
||||
)}
|
||||
<Grid alignItems="center" display="flex" size={4}>
|
||||
<Typography variant="body1">Order</Typography>
|
||||
</Grid>
|
||||
<Grid size={8}>
|
||||
<Controller
|
||||
name="order"
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={state.isDisabled}
|
||||
error={methods.formState.errors.siteUrl ? true : false}
|
||||
fullWidth
|
||||
helperText={
|
||||
methods.formState.errors.siteUrl
|
||||
? methods.formState.errors.siteUrl.message?.toString()
|
||||
: undefined
|
||||
}
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid alignItems="center" display="flex" size={4}>
|
||||
<Typography variant="body1">Title</Typography>
|
||||
</Grid>
|
||||
<Grid size={8}>
|
||||
<Controller
|
||||
name="title"
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={state.isDisabled}
|
||||
error={methods.formState.errors.title ? true : false}
|
||||
fullWidth
|
||||
helperText={
|
||||
methods.formState.errors.title
|
||||
? methods.formState.errors.title.message?.toString()
|
||||
: undefined
|
||||
}
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid alignItems="center" display="flex" size={4}>
|
||||
<Typography variant="body1">Sub Title</Typography>
|
||||
</Grid>
|
||||
<Grid size={8}>
|
||||
<Controller
|
||||
name="subTitle"
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={state.isDisabled}
|
||||
error={methods.formState.errors.siteUrl ? true : false}
|
||||
fullWidth
|
||||
helperText={
|
||||
methods.formState.errors.siteUrl
|
||||
? methods.formState.errors.siteUrl.message?.toString()
|
||||
: undefined
|
||||
}
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid alignItems="center" display="flex" size={4}>
|
||||
<Typography variant="body1">Icon Name</Typography>
|
||||
</Grid>
|
||||
<Grid size={8}>
|
||||
<Controller
|
||||
name="iconName"
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={state.isDisabled}
|
||||
error={methods.formState.errors.iconName ? true : false}
|
||||
fullWidth
|
||||
helperText={
|
||||
methods.formState.errors.iconName
|
||||
? methods.formState.errors.iconName.message?.toString()
|
||||
: undefined
|
||||
}
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid alignItems="center" display="flex" size={4}>
|
||||
<Typography variant="body1">Repo Name</Typography>
|
||||
</Grid>
|
||||
<Grid size={8}>
|
||||
<Controller
|
||||
name="repoName"
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={state.isDisabled}
|
||||
error={methods.formState.errors.repoName ? true : false}
|
||||
fullWidth
|
||||
helperText={
|
||||
methods.formState.errors.repoName
|
||||
? methods.formState.errors.repoName.message?.toString()
|
||||
: undefined
|
||||
}
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid alignItems="center" display="flex" size={4}>
|
||||
<Typography variant="body1">Site URL</Typography>
|
||||
</Grid>
|
||||
<Grid size={8}>
|
||||
<Controller
|
||||
name="siteUrl"
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={state.isDisabled}
|
||||
error={methods.formState.errors.siteUrl ? true : false}
|
||||
fullWidth
|
||||
helperText={
|
||||
methods.formState.errors.siteUrl
|
||||
? methods.formState.errors.siteUrl.message?.toString()
|
||||
: undefined
|
||||
}
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid alignItems="center" display="flex" size={4}>
|
||||
<Typography variant="body1">Summary</Typography>
|
||||
</Grid>
|
||||
<Grid size={8}>
|
||||
<Controller
|
||||
name="summary"
|
||||
control={methods.control}
|
||||
render={({ field: { onChange, value } }) => (
|
||||
<TextField
|
||||
disabled={state.isDisabled}
|
||||
error={methods.formState.errors.summary ? true : false}
|
||||
fullWidth
|
||||
helperText={
|
||||
methods.formState.errors.summary
|
||||
? methods.formState.errors.summary.message?.toString()
|
||||
: undefined
|
||||
}
|
||||
multiline
|
||||
maxRows={5}
|
||||
onChange={onChange}
|
||||
value={value}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid display="flex" gap={2} justifyContent="right" size={12}>
|
||||
<Button
|
||||
disabled={
|
||||
state.isDisabled && mode.toString() !== FormMode.VIEW
|
||||
? state.isDisabled
|
||||
: false
|
||||
}
|
||||
startIcon={<Icon iconName={IconName.XMARK} />}
|
||||
variant="outlined"
|
||||
onClick={onCancel}
|
||||
size="small"
|
||||
>
|
||||
{mode.toString() !== FormMode.VIEW ? 'Cancel' : 'Close'}
|
||||
</Button>
|
||||
{mode.toString() !== FormMode.VIEW && (
|
||||
<Button
|
||||
disabled={state.isDisabled}
|
||||
startIcon={<Icon iconName={IconName.SAVE} />}
|
||||
size="small"
|
||||
type="submit"
|
||||
variant="contained"
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
</form>
|
||||
</FormProvider>
|
||||
</Drawer>
|
||||
)
|
||||
}
|
||||
|
||||
export default ProjectForm;
|
||||
@@ -0,0 +1,8 @@
|
||||
import { FormMode } from "../../enums/formMode";
|
||||
|
||||
export interface ProjectFormProps {
|
||||
projectId?: string;
|
||||
isDrawerOpen: boolean;
|
||||
mode: FormMode;
|
||||
onOpenClose: (mode: FormMode) => void;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
export interface ProjectFormState {
|
||||
error: string | undefined;
|
||||
isDisabled: boolean;
|
||||
isLoading: boolean;
|
||||
}
|
||||
41
app/src/components/projectForm/reducer.ts
Normal file
41
app/src/components/projectForm/reducer.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { ProjectFormState } from "./ProjectFormState.interface"
|
||||
|
||||
type Action =
|
||||
| { type: 'SET_ERROR'; payload: string | undefined }
|
||||
| { type: 'SET_IS_DISABLED'; payload: boolean }
|
||||
| { type: 'SET_IS_LOADING'; payload: boolean }
|
||||
|
||||
export const initialState: ProjectFormState = {
|
||||
error: undefined,
|
||||
isDisabled: false,
|
||||
isLoading: true,
|
||||
};
|
||||
|
||||
export const reducer = (
|
||||
state: ProjectFormState,
|
||||
action: Action
|
||||
): ProjectFormState => {
|
||||
switch (action.type) {
|
||||
case 'SET_ERROR': {
|
||||
return {
|
||||
...state,
|
||||
error: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_IS_DISABLED': {
|
||||
return {
|
||||
...state,
|
||||
isDisabled: action.payload
|
||||
};
|
||||
}
|
||||
case 'SET_IS_LOADING': {
|
||||
return {
|
||||
...state,
|
||||
isLoading: action.payload
|
||||
};
|
||||
}
|
||||
default: {
|
||||
return state;
|
||||
}
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user