Skip to content

Commit

Permalink
feat: [contracts] wip create / view / edit contracts
Browse files Browse the repository at this point in the history
  • Loading branch information
dragos1195 committed Sep 23, 2024
1 parent 5912a47 commit 56b4cc5
Show file tree
Hide file tree
Showing 12 changed files with 73 additions and 34 deletions.
2 changes: 2 additions & 0 deletions frontend/src/assets/locales/ro/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1019,6 +1019,8 @@
},
"doc_templates": {
"title": "Creează template",
"view_title": "Vizualizează template",
"edit_title": "Editează template",
"subheading": {
"p1": "Acest template a fost realizat respectând normele din domeniu.",
"p1_link": "Află mai multe",
Expand Down
5 changes: 0 additions & 5 deletions frontend/src/common/constants/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,6 @@ export const ROUTES: IRoute[] = [
name: 'Contracte',
href: 'documents/templates',
},
{
id: 63,
name: 'Creează template',
href: 'documents/templates/create',
},
{
id: 64,
name: 'Generează contract',
Expand Down
9 changes: 5 additions & 4 deletions frontend/src/components/DocumentTemplatesTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { SortOrder, TableColumn } from 'react-data-table-component';
import { DocumentTemplatesProps } from '../containers/query/DocumentTemplatesTableWithQueryParams';
import { ArrowDownTrayIcon, EyeIcon, PencilIcon, TrashIcon } from '@heroicons/react/24/outline';
import Popover from './Popover';
import { Link } from 'react-router-dom';
import { Link, useNavigate } from 'react-router-dom';

const createArchiveRoute = (name: string) => `/actions-archive?author=${name.split(' ').join('+')}`;

Expand Down Expand Up @@ -62,6 +62,7 @@ const DocumentTemplatesTableHeader = [

export const DocumentTemplatesTable = ({ query, setQuery }: DocumentTemplatesProps) => {
const { t } = useTranslation(['doc_templates']);
const navigate = useNavigate();

const { data: templates, isLoading: isLoadingDocumentTemplates } = useDocumentTemplatesQuery({
limit: 10,
Expand Down Expand Up @@ -108,12 +109,12 @@ export const DocumentTemplatesTable = ({ query, setQuery }: DocumentTemplatesPro
{
label: t('table.table_actions.view'),
icon: <EyeIcon className="menu-icon" />,
onClick: () => { },
onClick: (row: IDocumentTemplateListItem) => { navigate(`${row.id}`) },
},
{
label: t('table.table_actions.edit'),
icon: <PencilIcon className="menu-icon" />,
onClick: () => { },
onClick: (row: IDocumentTemplateListItem) => { navigate(`${row.id}/edit`) },
},
{
label: t('table.table_actions.download_uncompleted'),
Expand All @@ -132,7 +133,7 @@ export const DocumentTemplatesTable = ({ query, setQuery }: DocumentTemplatesPro
{
label: t('table.table_actions.view'),
icon: <EyeIcon className="menu-icon" />,
onClick: () => { },
onClick: (row: IDocumentTemplateListItem) => { navigate(`${row.id}`) },
},
{
label: t('table.table_actions.download_uncompleted'),
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/components/RichText/RichTextEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,15 @@ const RichTextEditor = ({
onChange,
error,
className,
readonly,
}: {
onChange: (value: string) => void;
value: string;
error?: FieldError | Merge<FieldError, FieldErrorsImpl> | undefined;
className?: string;
readonly?: boolean;
}) => {
const { t } = useTranslation('doc_templates');
console.log('error', error);

return (
<div className="flex flex-col gap-4">
Expand All @@ -27,6 +28,7 @@ const RichTextEditor = ({
theme="snow"
onChange={onChange}
value={value}
readOnly={readonly}
// this bottom margin is NECESSARY due to the default styling, which sets the height of 100% to the text editor, but it doesn't take into consideration the toolbar height
className={`mb-10 border-2 border-cool-gray-900 rounded min-h-[10rem] max-h-[40rem] ${error && 'border-2 border-red-500'} ${className}`}
/>
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/components/contracts/ContractTemplatePreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ export const ContractTemplatePreview = ({
reset,
getValues,
formErrors,
readonly,
termsValue,
}: {
control: Control<FieldValues>;
reset: UseFormReset<FieldValues>;
getValues: UseFormGetValues<FieldValues>;
formErrors: FieldErrors<FieldValues>;
readonly?: boolean;
termsValue: string;
}) => {
const { t } = useTranslation('doc_templates');
const [infoParagraphHovered, setInfoParagraphHovered] = useState(false);
Expand Down Expand Up @@ -157,6 +161,8 @@ export const ContractTemplatePreview = ({
reset={reset}
getValues={getValues}
formErrors={formErrors}
readonly={readonly}
termsValue={termsValue}
/>
<Signatures
organization={{
Expand Down
20 changes: 15 additions & 5 deletions frontend/src/components/contracts/ContractTerms.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import React, { useEffect, useState } from 'react';
import {
Control,
Controller,
Expand All @@ -18,17 +18,27 @@ export const ContractTerms = ({
reset,
getValues,
formErrors,
readonly,
termsValue,
}: {
control: Control<FieldValues>;
reset: UseFormReset<FieldValues>;
getValues: UseFormGetValues<FieldValues>;
formErrors: FieldErrors<FieldValues>;
readonly?: boolean;
termsValue?: string;
}) => {
const { t } = useTranslation(['doc_templates', 'general']);
const [editingText, setEditingText] = useState(false);

// todo: initial value for contractTerms taken from the template
const [contractTerms, setContractTerms] = useState<string>('');
const [contractTerms, setContractTerms] = useState<string>(termsValue || '')

useEffect(() => {
if (termsValue && termsValue !== contractTerms) {
setContractTerms(termsValue || '');
}
}, [termsValue]);

const onSave = () => {
const newContractTerms = getValues('contractTerms');
Expand All @@ -53,7 +63,7 @@ export const ContractTerms = ({
field: { value: string; onChange: (value: string) => void };
}) => {
return (
<RichTextEditor value={value} onChange={onChange} error={formErrors.contractTerms} />
<RichTextEditor value={value} onChange={onChange} error={formErrors.contractTerms} readonly={readonly} />
);
}}
/>
Expand All @@ -78,10 +88,10 @@ export const ContractTerms = ({
);
}

if (!contractTerms) {
if (!contractTerms && !readonly) {
return (
<ContractTermsEmptyState setEditingText={setEditingText} error={formErrors.contractTerms} />
);
} // normal text
return <ContractTermsContent innerContent={contractTerms} setEditingText={setEditingText} />;
return <ContractTermsContent innerContent={contractTerms} setEditingText={setEditingText} readonly={readonly} />;
};
6 changes: 4 additions & 2 deletions frontend/src/components/contracts/ContractTermsContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,24 @@ import DOMPurify from 'dompurify';
export const ContractTermsContent = ({
innerContent,
setEditingText,
readonly,
}: {
innerContent: string;
setEditingText: React.Dispatch<React.SetStateAction<boolean>>;
readonly?: boolean
}) => {
const { t } = useTranslation('doc_templates');

return (
<div className="flex flex-col gap-4 my-4 py-8 border-y-2 border-dashed">
<div className="flex flex-row justify-between items-center">
<p className="font-robotoBold">{t('contract_terms.title')}</p>
<Button
{!readonly && <Button
className="btn-outline-secondary text-cool-gray-500"
label={t('text_editor.title')}
icon={<PencilIcon className="h-5 w-5 text-cool-gray-500" />}
onClick={() => setEditingText(true)}
/>
/>}
</div>
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(innerContent || '') }} />
</div>
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/components/contracts/OrganizationDetails.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { useResyncOrganizationWithOngHubMutation } from '../../services/organiza
import Button from '../Button';
import { useQueryClient } from 'react-query';

export const OrganizationDetails = ({ control }: { control: Control<FieldValues> }) => {
export const OrganizationDetails = ({ control, readonly }: { control: Control<FieldValues>, readonly?: boolean }) => {
const { t } = useTranslation(['doc_templates', 'general']);

const queryClient = useQueryClient();
Expand Down Expand Up @@ -35,6 +35,7 @@ export const OrganizationDetails = ({ control }: { control: Control<FieldValues>
? t('required', { ns: 'general' })
: undefined
}
readOnly={readonly}
/>
);
}}
Expand Down
46 changes: 32 additions & 14 deletions frontend/src/pages/CreateContractTemplate.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useMemo } from 'react';
import React, { useEffect, useMemo } from 'react';
import PageLayout from '../layouts/PageLayout';
import PageHeader from '../components/PageHeader';
import { useNavigate } from 'react-router-dom';
import { useNavigate, useParams } from 'react-router-dom';
import CardHeader from '../components/CardHeader';
import Card from '../layouts/CardLayout';
import CardBody from '../components/CardBody';
Expand All @@ -16,9 +16,18 @@ import { Tooltip } from 'react-tooltip';
import {
IAddContractTemplatePayload,
useAddContractTemplateMutation,
useDocumentTemplateByIdQuery,
} from '../services/documents-templates/documents-templates.service';
import { IDocumentTemplate } from '../common/interfaces/template.interface';

interface CreateContractTemplateProps {
template?: IDocumentTemplate;
readonly?: boolean;
}

export const CreateContractTemplate = ({ readonly }: CreateContractTemplateProps) => {
const { id } = useParams();

export const CreateContractTemplate = () => {
const navigate = useNavigate();

const { t } = useTranslation(['doc_templates', 'general']);
Expand All @@ -30,6 +39,19 @@ export const CreateContractTemplate = () => {
setError,
formState: { errors },
} = useForm();

const { data: template } = useDocumentTemplateByIdQuery(id);
const contractTerms = getValues('contractTerms');

useEffect(() => {
if (template) {
reset({
templateName: template.name,
contractTerms: template.documentTerms,
});
}
}, [template]);

const { data: organization } = useOrganizationQuery();
const isOrganizationDataComplete = useMemo(
() =>
Expand All @@ -40,13 +62,10 @@ export const CreateContractTemplate = () => {
organization?.legalReprezentativeRole,
[organization],
);
console.log('errors', errors);
const { mutate: addContractTemplate, isLoading: isLoadingAddContractTemplate } =
useAddContractTemplateMutation();

const onSubmit = ({ templateName, contractTerms }: FieldValues) => {
console.log('templateName', templateName);
console.log('contractTerms', contractTerms);
if (!contractTerms) {
return setError('contractTerms', {
type: 'required',
Expand All @@ -64,6 +83,7 @@ export const CreateContractTemplate = () => {
},
documentTerms: contractTerms,
} as IAddContractTemplatePayload;

addContractTemplate(contractTemplateData, {
onSuccess: () => {
//todo
Expand All @@ -75,15 +95,12 @@ export const CreateContractTemplate = () => {
};

const navigateBack = () => {
// todo: this should send us back to the templates tab
navigate('/documents/templates', { replace: true });
};

// TODO: links for <a/>

return (
<PageLayout>
<PageHeader onBackButtonPress={navigateBack}>{t('title')}</PageHeader>
<PageHeader onBackButtonPress={navigateBack}>{readonly ? t('view_title') : template ? t('edit_title') : t('title')}</PageHeader>

{/* sub header text */}
<div className="flex flex-col gap-2">
Expand All @@ -106,15 +123,14 @@ export const CreateContractTemplate = () => {
<CardHeader>
<div className="flex flex-row justify-between w-full items-center">
<h2>{t('table_header.title')} </h2>
<div className="flex flex-row gap-2">
{!readonly && <div className="flex flex-row gap-2">
<Button
label={t('table_header.download_uncompleted')}
icon={<ArrowDownTrayIcon className="h-5 w-5 text-cool-gray-600" />}
className="btn-outline-secondary text-cool-gray-600 "
// TODO: descarca necompletat functionality
onClick={() => { }}
/>
{/* // TODO: save functionality */}
<Button
data-tooltip-id="save-btn-tooltip-incompleteData"
disabled={!isOrganizationDataComplete || isLoadingAddContractTemplate}
Expand Down Expand Up @@ -143,19 +159,21 @@ export const CreateContractTemplate = () => {
}}
/>
)}
</div>
</div>}
</div>
</CardHeader>

{/* TABLE BODY */}
<CardBody>
<div className="flex flex-col gap-4 md:flex-row">
<OrganizationDetails control={control} />
<OrganizationDetails control={control} readonly={readonly} />
<ContractTemplatePreview
control={control}
reset={reset}
getValues={getValues}
formErrors={errors}
readonly={readonly}
termsValue={contractTerms}
/>
</div>
</CardBody>
Expand Down
2 changes: 2 additions & 0 deletions frontend/src/routes/Router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ const Router = () => {
</Route>
<Route path="templates" element={<Outlet />}>
<Route index element={<DocumentContracts />} />
<Route path=':id' element={<CreateContractTemplate readonly />} />
<Route path=':id/edit' element={<CreateContractTemplate />} />
<Route path="create" element={<CreateContractTemplate />} />
<Route path="contracts" element={<Outlet />}>
<Route path="generate" element={<GenerateContract />} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export const getTemplates = async (params: {
return API.get('documents/templates', { params }).then((res) => res.data);
};

export const getTemplateById = async (id: string): Promise<IDocumentTemplate> => {
export const getTemplateById = async (id?: string): Promise<IDocumentTemplate> => {
return API.get(`/documents/templates/${id}`).then((res) => res.data);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export const useDocumentTemplatesQuery = ({
);
};

export const useDocumentTemplateByIdQuery = (id: string) => {
export const useDocumentTemplateByIdQuery = (id?: string) => {
return useQuery({
queryKey: ['document-template', id],
queryFn: () => getTemplateById(id),
Expand Down

0 comments on commit 56b4cc5

Please sign in to comment.