Skip to content

Commit

Permalink
[FS-268]: Project Documents Add A New Document (#137)
Browse files Browse the repository at this point in the history
This PR projects documents add a new document.

---------

Co-authored-by: Alireza Safaierad <frontendmonster@gmail.com>
  • Loading branch information
AmirabbasJ and ASafaeirad authored Jan 8, 2024
1 parent e8a9672 commit a62b7d5
Show file tree
Hide file tree
Showing 30 changed files with 524 additions and 56 deletions.
5 changes: 3 additions & 2 deletions app/Dashboard/Projects/ProjectDetail/ProjectDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { isEmpty, isNull } from '@fullstacksjs/toolbox';
import { Text, Title } from '@mantine/core';

import { ProjectStatusBadge } from '../_components/ProjectStatusBadge';
import { ProjectDocuments } from './_components/ProjectDocuments';
import { ProjectDetailIds as ids } from './ProjectDetail.ids';

export const ProjectDetail = () => {
Expand Down Expand Up @@ -77,8 +78,8 @@ export const ProjectDetail = () => {
id: ids.membersTab,
},
{
tab: <Title order={5}>{t.tabs.albumTitle}</Title>,
panel: <div />,
tab: <Title order={5}>{t.tabs.documentsTitle}</Title>,
panel: <ProjectDocuments />,
id: ids.albumTab,
},
]}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { CreateProjectDocumentButton } from './CreateProjectDocumentButton';
import { createProjectDocumentButtonId } from './CreateProjectDocumentButton.ids';

describe('Create Project Button', () => {
beforeEach(() => {
cy.mount(<CreateProjectDocumentButton />);
});

it('should be visible to users', () => {
cy.findByTestId(createProjectDocumentButtonId).should('exist');
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const createProjectDocumentButtonId = 'create-document';
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import type { Meta, StoryObj } from '@storybook/react';

import { CreateProjectDocumentButton } from './CreateProjectDocumentButton';

export default {
component: CreateProjectDocumentButton,
} as Meta<typeof CreateProjectDocumentButton>;

type Story = StoryObj<typeof CreateProjectDocumentButton>;

export const Default: Story = {};
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { PlusIcon } from '@camp/icons';
import { messages } from '@camp/messages';
import { tid } from '@camp/test';
import { Button } from '@mantine/core';

import { openCreateProjectDocumentModal } from '../CreateProjectDocumentModal';
import { createProjectDocumentButtonId as id } from './CreateProjectDocumentButton.ids';

export const CreateProjectDocumentButton = () => {
const t = messages.projectDetail.addDocument;

return (
<Button
variant="outline"
size="sm"
{...tid(id)}
onClick={openCreateProjectDocumentModal}
leftIcon={<PlusIcon size={16} />}
>
{t.addDocBtn}
</Button>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './CreateProjectDocumentButton';
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export const createProjectDocumentFormIds = {
form: 'create-project-document-form',
dateInput: 'project-document-date',
descriptionInput: 'project-description-input',
submitBtn: 'submit-button',
notification: {
success: 'create-project-document-success-notification',
failure: 'create-project-document-failure-notification',
},
} as const;
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import { debug, DebugScopes } from '@camp/debug';
import {
ControlledDateInput,
ControlledFileUpload,
FileUpload,

Check warning on line 5 in app/Dashboard/Projects/ProjectDetail/_components/CreateProjectDocument/CreateProjectDocumentForm/CreateProjectDocumentForm.tsx

View workflow job for this annotation

GitHub Actions / verify

'FileUpload' is defined but never used. Allowed unused vars must match /^([iI]gnore(d)?)|(_+)/u
showNotification,
} from '@camp/design';
import {
createResolver,
documentFileValidator,
documentSchema,
} from '@camp/domain';
import { messages } from '@camp/messages';
import { tid } from '@camp/test';
import { Button, createStyles, Group, Stack, TextInput } from '@mantine/core';
import { Controller, useForm } from 'react-hook-form';

Check warning on line 16 in app/Dashboard/Projects/ProjectDetail/_components/CreateProjectDocument/CreateProjectDocumentForm/CreateProjectDocumentForm.tsx

View workflow job for this annotation

GitHub Actions / verify

'Controller' is defined but never used. Allowed unused vars must match /^([iI]gnore(d)?)|(_+)/u
import type { SafeParseError, SafeParseSuccess } from 'zod';

import { createProjectDocumentFormIds as ids } from './CreateProjectDocumentForm.ids';

interface FormSchema {
date: Date;
description: string;
documents: File[];
}

interface Props {
dismiss: () => void;
}

const resolver = createResolver<FormSchema>({
date: documentSchema.date(),
description: documentSchema.description(),
documents: documentSchema.documents(),
});

const useStyle = createStyles(theme => ({
label: {
label: {
color: theme.colors.fg[6],
},
},
}));

// FIXME replace with actual upload

Check warning on line 45 in app/Dashboard/Projects/ProjectDetail/_components/CreateProjectDocument/CreateProjectDocumentForm/CreateProjectDocumentForm.tsx

View workflow job for this annotation

GitHub Actions / verify

Unexpected 'fixme' comment: 'FIXME replace with actual upload'

// eslint-disable-next-line fp/no-let
let x = 0;

const uploadDocument = () => {
return new Promise<void>((res, rej) => {

Check warning on line 51 in app/Dashboard/Projects/ProjectDetail/_components/CreateProjectDocument/CreateProjectDocumentForm/CreateProjectDocumentForm.tsx

View workflow job for this annotation

GitHub Actions / verify

Promise constructor parameters must be named to match "^_?resolve$"

Check warning on line 51 in app/Dashboard/Projects/ProjectDetail/_components/CreateProjectDocument/CreateProjectDocumentForm/CreateProjectDocumentForm.tsx

View workflow job for this annotation

GitHub Actions / verify

Promise constructor parameters must be named to match "^_?reject$"
setTimeout(() => {
x++;
if (x === 3) rej();
else res();
}, 1000);
});
};

const unUploadDocument = () => {
return uploadDocument();
};

export const CreateProjectDocumentForm = ({ dismiss }: Props) => {
const t = messages.projectDetail.addDocument.form;
const { handleSubmit, register, formState, control } = useForm<FormSchema>({
resolver,
mode: 'onChange',
});

const onSubmit = handleSubmit(data => {
debug.log(DebugScopes.All, data);
});

const { classes } = useStyle();
return (
<form onSubmit={onSubmit} {...tid(ids.form)}>
<Stack spacing={40}>
<ControlledDateInput
name="date"
control={control}
className={classes.label}
wrapperProps={tid(ids.dateInput)}
label={t.dateInput.label}
placeholder={t.dateInput.placeholder}
error={formState.errors.date?.message}
/>
<TextInput
wrapperProps={tid(ids.descriptionInput)}
required
{...register('description')}
label={t.descriptionInput.label}
placeholder={t.descriptionInput.placeholder}
error={formState.errors.description?.message}
/>
<ControlledFileUpload
control={control}
name="documents"
defaultValue={[]}
required
label={t.documentsInput.label}
helper={t.documentsInput.maxSize}
upload={uploadDocument}
unUpload={unUploadDocument}
filter={(files): File[] => {
const res = files.map(f => documentFileValidator.safeParse(f));
const firstError = res.find(
r => !r.success,
) as SafeParseError<File> | null;

if (firstError != null)
showNotification({
message: firstError.error.issues[0]!.message,
type: 'failure',
});
return res
.filter((r): r is SafeParseSuccess<File> => r.success)
.map(r => r.data);
}}
/>

<Group spacing={10} position="right">
<Button
size="sm"
variant="filled"
color="secondary"
onClick={dismiss}
>
{messages.actions.dismiss}
</Button>
<Button
type="submit"
size="sm"
disabled={!formState.isValid}
{...tid(ids.submitBtn)}
>
{t.submitBtn}
</Button>
</Group>
</Stack>
</form>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './CreateProjectDocumentForm';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const createProjectDocumentModalId = 'create-project-document-modal';
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { ModalsProvider } from '@mantine/modals';
import type { Meta, StoryObj } from '@storybook/react';
import { useEffect } from 'react';

import {
CreateProjectDocumentModal,
openCreateProjectDocumentModal,
} from './CreateProjectDocumentModal';

export default {
argTypes: {
opened: {
defaultValue: true,
type: 'boolean',
description: 'Mounts modal if true',
},
},
component: CreateProjectDocumentModal,
decorators: [
Story => (
<ModalsProvider>
<Story />
</ModalsProvider>
),
],
chromatic: { delay: 500 },
} as Meta<typeof CreateProjectDocumentModal>;

type Story = StoryObj<typeof CreateProjectDocumentModal>;

export const Default: Story = {
render: () => {
useEffect(() => {
openCreateProjectDocumentModal();
}, []);

return <></>;
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { messages } from '@camp/messages';
import { tid } from '@camp/test';
import { closeModal, openModal } from '@mantine/modals';

import { CreateProjectDocumentForm } from '../CreateProjectDocumentForm';
import { createProjectDocumentModalId as id } from './CreateProjectDocumentModal.ids';

export const CreateProjectDocumentModal = () => (
<CreateProjectDocumentForm dismiss={() => closeModal(id)} />
);

export const openCreateProjectDocumentModal = () =>
openModal({
modalId: id,
children: <CreateProjectDocumentModal />,
title: messages.projectDetail.addDocument.title,
size: '490',
padding: '30px',
centered: true,
...tid(id),
});
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './CreateProjectDocumentModal';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './CreateProjectDocumentButton';
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { DashboardTitle } from '@camp/design';
import { messages } from '@camp/messages';
import { Group, Stack } from '@mantine/core';

import { CreateProjectDocumentButton } from '../CreateProjectDocument';

export const ProjectDocuments = () => {
const t = messages.projectDetail.addDocument;

return (
<Stack spacing={25} sx={{ position: 'relative' }}>
<Group position="apart" mih="100%">
<DashboardTitle>{t.title}</DashboardTitle>
<CreateProjectDocumentButton />
</Group>
</Stack>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './ProjectDocuments';
28 changes: 26 additions & 2 deletions app/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ export const messages = {
nextPage: 'صفحه بعد',
},
notification: {
addDocument: {
unsupportedType: 'فایل انتخاب شده پشتیبانی نمی‌شود',
maxSizeExceeded: 'حداکثر سایز فایل انتخابی ۲۰ مگابایت هست.',
},
household: {
delete: {
title: 'حذف خانوار',
Expand Down Expand Up @@ -59,6 +63,10 @@ export const messages = {
format: (date: Date) => new Intl.DateTimeFormat('fa-IR').format(date),
},
validation: {
document: {
required: 'فایل الزامی',
unsupportedExtension: 'فایل مجاز نیست',
},
dob: {
max: 'تاریخ تولد نمی‌تواند آینده باشد',
},
Expand Down Expand Up @@ -359,7 +367,7 @@ export const messages = {
title: 'اطلاعات پروژه',
notFound: 'اطلاعات پروژه یافت نشد',
tabs: {
albumTitle: 'آلبوم',
documentsTitle: 'اسناد',
membersTitle: 'اعضا',
},
panels: {
Expand All @@ -385,9 +393,25 @@ export const messages = {
},
},
addDocument: {
form: {
dateInput: {
label: 'تاریخ',
placeholder: '۱۴۰۰/۰۱/۰۱',
},
descriptionInput: {
label: 'توضیحات',
placeholder: 'توضیحات',
},
documentsInput: {
label: 'اسناد',
maxSize: 'فایل باید کمتر از ۲۰ مگابایت باشد',
},
submitBtn: 'ایجاد سند',
},
title: 'ایجاد سند جدید',
description: 'توضیحات',
addDocBtn: 'بارگذاری سند',
addDocBtn: 'افزودن',
addDocFileBtn: 'بارگذاری سند',
note: 'سند را اینجا قرار دهید',
},
},
Expand Down
1 change: 1 addition & 0 deletions configs/cspell/charity.en.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,4 @@ huskyrc
indexify
pkey
alian
Prray
Loading

0 comments on commit a62b7d5

Please sign in to comment.