From 632c4629def3e9406352209ee62439794ecaa7b1 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Thu, 12 Sep 2024 14:16:07 +0200 Subject: [PATCH] feat: hook up the invice customize api --- .../PdfTemplates/PdfTemplatesController.ts | 9 +- .../services/PdfTemplate/EditPdfTemplate.ts | 13 ++- .../src/components/Drawer/DrawerProvider.tsx | 9 +- .../ElementCustomizeFields.tsx | 3 +- .../BrandingTemplateBoot.tsx | 50 ++++++++ .../BrandingTemplatesContent.tsx | 8 +- .../BrandingTemplatesTable.tsx | 3 +- .../InvoiceCustomize/InvoiceCustomize.tsx | 103 ++--------------- .../InvoiceCustomizeContent.tsx | 109 ++++++++++++++++++ .../InvoiceCustomizeDrawer.tsx | 8 +- .../InvoiceCustomizeForm.schema.ts | 5 + .../InvoiceCustomizeGeneralFields.tsx | 95 +++++++++------ .../InvoiceCutomizeContentFields.tsx | 2 +- .../InvoiceCustomize/Overlay.module.scss | 19 +++ .../Invoices/InvoiceCustomize/Overlay.tsx | 20 ++++ .../Invoices/InvoiceCustomize/constants.ts | 2 + .../Sales/Invoices/InvoiceCustomize/types.ts | 2 + .../Sales/Invoices/InvoiceCustomize/utils.ts | 37 +++++- .../InvoicesLanding/InvoicesActionsBar.tsx | 2 +- .../webapp/src/hooks/query/pdf-templates.ts | 52 +++++++-- packages/webapp/src/hooks/state/dashboard.tsx | 9 ++ 21 files changed, 391 insertions(+), 169 deletions(-) create mode 100644 packages/webapp/src/containers/Sales/Invoices/BrandingTemplates/BrandingTemplateBoot.tsx create mode 100644 packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeContent.tsx create mode 100644 packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeForm.schema.ts create mode 100644 packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/Overlay.module.scss create mode 100644 packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/Overlay.tsx diff --git a/packages/server/src/api/controllers/PdfTemplates/PdfTemplatesController.ts b/packages/server/src/api/controllers/PdfTemplates/PdfTemplatesController.ts index 2e6821bdb..172070a80 100644 --- a/packages/server/src/api/controllers/PdfTemplates/PdfTemplatesController.ts +++ b/packages/server/src/api/controllers/PdfTemplates/PdfTemplatesController.ts @@ -26,20 +26,21 @@ export class PdfTemplatesController extends BaseController { '/:template_id', [ param('template_id').exists().isInt().toInt(), + check('template_name').exists(), check('attributes').exists(), ], this.validationResult, this.editPdfTemplate.bind(this) ); + router.get('/', this.getPdfTemplates.bind(this)); router.get( '/:template_id', [param('template_id').exists().isInt().toInt()], this.validationResult, this.getPdfTemplate.bind(this) ); - router.get('/', this.getPdfTemplates.bind(this)); router.post( - '/invoices', + '/', [check('template_name').exists(), check('attributes').exists()], this.validationResult, this.createPdfInvoiceTemplate.bind(this) @@ -70,13 +71,13 @@ export class PdfTemplatesController extends BaseController { async editPdfTemplate(req: Request, res: Response, next: NextFunction) { const { tenantId } = req; const { template_id: templateId } = req.params; - const { attributes } = this.matchedBodyData(req); + const editTemplateDTO = this.matchedBodyData(req); try { const result = await this.pdfTemplateApplication.editPdfTemplate( tenantId, Number(templateId), - attributes + editTemplateDTO ); return res.status(200).send(result); } catch (error) { diff --git a/packages/server/src/services/PdfTemplate/EditPdfTemplate.ts b/packages/server/src/services/PdfTemplate/EditPdfTemplate.ts index 27a57b543..0e94a2c61 100644 --- a/packages/server/src/services/PdfTemplate/EditPdfTemplate.ts +++ b/packages/server/src/services/PdfTemplate/EditPdfTemplate.ts @@ -30,11 +30,14 @@ export class EditPdfTemplate { const { PdfTemplate } = this.tenancy.models(tenantId); return this.uow.withTransaction(tenantId, async (trx) => { - await PdfTemplate.query(trx) - .patch({ - ...editTemplateDTO, - }) - .where('id', templateId); + await this.eventPublisher.emitAsync(events.pdfTemplate.onEditing, { + tenantId, + templateId, + }); + await PdfTemplate.query(trx).where('id', templateId).update({ + templateName: editTemplateDTO.templateName, + attributes: editTemplateDTO.attributes, + }); await this.eventPublisher.emitAsync(events.pdfTemplate.onEdited, { tenantId, diff --git a/packages/webapp/src/components/Drawer/DrawerProvider.tsx b/packages/webapp/src/components/Drawer/DrawerProvider.tsx index f89256ba0..e5c8ebad2 100644 --- a/packages/webapp/src/components/Drawer/DrawerProvider.tsx +++ b/packages/webapp/src/components/Drawer/DrawerProvider.tsx @@ -1,7 +1,14 @@ // @ts-nocheck import React, { createContext, useContext } from 'react'; -const DrawerContext = createContext(); +interface DrawerContextValue { + name: string; + payload: Record; +} + +const DrawerContext = createContext( + {} as DrawerContextValue, +); /** * Account form provider. diff --git a/packages/webapp/src/containers/ElementCustomize/ElementCustomizeFields.tsx b/packages/webapp/src/containers/ElementCustomize/ElementCustomizeFields.tsx index 25294d3b1..c9846ecf6 100644 --- a/packages/webapp/src/containers/ElementCustomize/ElementCustomizeFields.tsx +++ b/packages/webapp/src/containers/ElementCustomize/ElementCustomizeFields.tsx @@ -47,7 +47,7 @@ export function ElementCustomizeFieldsMain() { function ElementCustomizeFooterActionsRoot({ closeDrawer }) { const { name } = useDrawerContext(); - const { submitForm } = useFormikContext(); + const { submitForm, isSubmitting } = useFormikContext(); const handleSubmitBtnClick = () => { submitForm(); @@ -62,6 +62,7 @@ function ElementCustomizeFooterActionsRoot({ closeDrawer }) { onClick={handleSubmitBtnClick} intent={Intent.PRIMARY} style={{ minWidth: 75 }} + loading={isSubmitting} > Save diff --git a/packages/webapp/src/containers/Sales/Invoices/BrandingTemplates/BrandingTemplateBoot.tsx b/packages/webapp/src/containers/Sales/Invoices/BrandingTemplates/BrandingTemplateBoot.tsx new file mode 100644 index 000000000..997436b07 --- /dev/null +++ b/packages/webapp/src/containers/Sales/Invoices/BrandingTemplates/BrandingTemplateBoot.tsx @@ -0,0 +1,50 @@ +import React, { createContext, useContext } from 'react'; +import { + GetPdfTemplateResponse, + useGetPdfTemplate, +} from '@/hooks/query/pdf-templates'; +import { Spinner } from '@blueprintjs/core'; + +interface PdfTemplateContextValue { + templateId: number | string; + pdfTemplate: GetPdfTemplateResponse | undefined; + isPdfTemplateLoading: boolean; +} + +interface BrandingTemplateProps { + templateId: number; + children: React.ReactNode; +} + +const PdfTemplateContext = createContext( + {} as PdfTemplateContextValue, +); + +export const BrandingTemplateBoot = ({ + templateId, + children, +}: BrandingTemplateProps) => { + const { data: pdfTemplate, isLoading: isPdfTemplateLoading } = + useGetPdfTemplate(templateId, { + enabled: !!templateId, + }); + + const value = { + templateId, + pdfTemplate, + isPdfTemplateLoading, + }; + + if (isPdfTemplateLoading) { + return + } + return ( + + {children} + + ); +}; + +export const useBrandingTemplateBoot = () => { + return useContext(PdfTemplateContext); +}; diff --git a/packages/webapp/src/containers/Sales/Invoices/BrandingTemplates/BrandingTemplatesContent.tsx b/packages/webapp/src/containers/Sales/Invoices/BrandingTemplates/BrandingTemplatesContent.tsx index cffad144f..cd7fd3e37 100644 --- a/packages/webapp/src/containers/Sales/Invoices/BrandingTemplates/BrandingTemplatesContent.tsx +++ b/packages/webapp/src/containers/Sales/Invoices/BrandingTemplates/BrandingTemplatesContent.tsx @@ -2,13 +2,7 @@ import * as R from 'ramda'; import { Button, Classes, Intent } from '@blueprintjs/core'; import { BrandingTemplatesBoot } from './BrandingTemplatesBoot'; -import { - Box, - Card, - DrawerBody, - DrawerHeaderContent, - Group, -} from '@/components'; +import { Box, Card, DrawerHeaderContent, Group } from '@/components'; import { DRAWERS } from '@/constants/drawers'; import { BrandingTemplatesTable } from './BrandingTemplatesTable'; import withDrawerActions from '@/containers/Drawer/withDrawerActions'; diff --git a/packages/webapp/src/containers/Sales/Invoices/BrandingTemplates/BrandingTemplatesTable.tsx b/packages/webapp/src/containers/Sales/Invoices/BrandingTemplates/BrandingTemplatesTable.tsx index 07164d26b..6ae205212 100644 --- a/packages/webapp/src/containers/Sales/Invoices/BrandingTemplates/BrandingTemplatesTable.tsx +++ b/packages/webapp/src/containers/Sales/Invoices/BrandingTemplates/BrandingTemplatesTable.tsx @@ -18,7 +18,6 @@ function BrandingTemplateTableRoot({ }: BrandingTemplatesTableProps) { // Table columns. const columns = useBrandingTemplatesColumns(); - const { isPdfTemplatesLoading, pdfTemplates } = useBrandingTemplatesBoot(); const handleEditTemplate = (template) => { @@ -70,7 +69,7 @@ const useBrandingTemplatesColumns = () => { Header: 'Template Name', accessor: (row) => ( - {row.template_name} Default + {row.template_name} {row.default && Default} ), width: 65, diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomize.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomize.tsx index 966a3cf9e..9ce80d618 100644 --- a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomize.tsx +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomize.tsx @@ -1,98 +1,19 @@ -import React from 'react'; -import * as R from 'ramda'; -import { AppToaster, Box } from '@/components'; -import { Classes, Intent } from '@blueprintjs/core'; -import { useFormikContext } from 'formik'; -import { - InvoicePaperTemplate, - InvoicePaperTemplateProps, -} from './InvoicePaperTemplate'; -import { ElementCustomize } from '../../../ElementCustomize/ElementCustomize'; -import { InvoiceCustomizeGeneralField } from './InvoiceCustomizeGeneralFields'; -import { InvoiceCustomizeContentFields } from './InvoiceCutomizeContentFields'; -import { InvoiceCustomizeValues } from './types'; -import { initialValues } from './constants'; -import { - useCreatePdfTemplate, - useEditPdfTemplate, -} from '@/hooks/query/pdf-templates'; -import { transformToEditRequest, transformToNewRequest } from './utils'; +// @ts-nocheck +import { Classes } from '@blueprintjs/core'; +import { useDrawerContext } from '@/components/Drawer/DrawerProvider'; +import { BrandingTemplateBoot } from '../BrandingTemplates/BrandingTemplateBoot'; +import { InvoiceCustomizeContent } from './InvoiceCustomizeContent'; +import { Box } from '@/components'; -export default function InvoiceCustomizeContent() { - const { mutateAsync: createPdfTemplate } = useCreatePdfTemplate(); - const { mutateAsync: editPdfTemplate } = useEditPdfTemplate(); - - const templateId: number = 1; - - const handleFormSubmit = (values: InvoiceCustomizeValues) => { - const handleSuccess = (message: string) => { - AppToaster.show({ - intent: Intent.SUCCESS, - message, - }); - }; - const handleError = (message: string) => { - AppToaster.show({ - intent: Intent.DANGER, - message, - }); - }; - if (templateId) { - const reqValues = transformToEditRequest(values, templateId); - - // Edit existing template - // editPdfTemplate({ templateId, values: reqValues }) - // .then(() => handleSuccess('PDF template updated successfully!')) - // .catch(() => - // handleError('An error occurred while updating the PDF template.'), - // ); - } else { - const reqValues = transformToNewRequest(values); - - // Create new template - createPdfTemplate(reqValues) - .then(() => handleSuccess('PDF template created successfully!')) - .catch(() => - handleError('An error occurred while creating the PDF template.'), - ); - } - }; +export default function InvoiceCustomize() { + const { payload } = useDrawerContext(); + const templateId = payload.templateId; return ( - - initialValues={initialValues} - onSubmit={handleFormSubmit} - > - - - - - - - - - - - - - - asdfasdfdsaf #3 - - + + + ); } - -const withFormikProps =

( - Component: React.ComponentType

, -) => { - return (props: Omit) => { - const { values } = useFormikContext(); - - return ; - }; -}; - -export const InvoicePaperTemplateFormConnected = - R.compose(withFormikProps)(InvoicePaperTemplate); diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeContent.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeContent.tsx new file mode 100644 index 000000000..ec4b4e056 --- /dev/null +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeContent.tsx @@ -0,0 +1,109 @@ +import React from 'react'; +import * as R from 'ramda'; +import { AppToaster } from '@/components'; +import { Intent } from '@blueprintjs/core'; +import { FormikHelpers, useFormikContext } from 'formik'; +import { + InvoicePaperTemplate, + InvoicePaperTemplateProps, +} from './InvoicePaperTemplate'; +import { ElementCustomize } from '../../../ElementCustomize/ElementCustomize'; +import { InvoiceCustomizeGeneralField } from './InvoiceCustomizeGeneralFields'; +import { InvoiceCustomizeContentFields } from './InvoiceCutomizeContentFields'; +import { InvoiceCustomizeValues } from './types'; +import { + useCreatePdfTemplate, + useEditPdfTemplate, +} from '@/hooks/query/pdf-templates'; +import { + transformToEditRequest, + transformToNewRequest, + useInvoiceCustomizeInitialValues, +} from './utils'; +import { InvoiceCustomizeSchema } from './InvoiceCustomizeForm.schema'; +import { useDrawerContext } from '@/components/Drawer/DrawerProvider'; +import { useDrawerActions } from '@/hooks/state'; + +export function InvoiceCustomizeContent() { + const { mutateAsync: createPdfTemplate } = useCreatePdfTemplate(); + const { mutateAsync: editPdfTemplate } = useEditPdfTemplate(); + + const { payload, name } = useDrawerContext(); + const { closeDrawer } = useDrawerActions(); + + const templateId = payload?.templateId || null; + + const handleFormSubmit = ( + values: InvoiceCustomizeValues, + { setSubmitting }: FormikHelpers, + ) => { + const handleSuccess = (message: string) => { + AppToaster.show({ intent: Intent.SUCCESS, message }); + setSubmitting(false); + closeDrawer(name); + }; + const handleError = (message: string) => { + AppToaster.show({ intent: Intent.DANGER, message }); + setSubmitting(false); + }; + if (templateId) { + const reqValues = transformToEditRequest(values); + setSubmitting(true); + + // Edit existing template + editPdfTemplate({ templateId, values: reqValues }) + .then(() => handleSuccess('PDF template updated successfully!')) + .catch(() => + handleError('An error occurred while updating the PDF template.'), + ); + } else { + const reqValues = transformToNewRequest(values); + setSubmitting(true); + + // Create new template + createPdfTemplate(reqValues) + .then(() => handleSuccess('PDF template created successfully!')) + .catch(() => + handleError('An error occurred while creating the PDF template.'), + ); + } + }; + const initialValues = useInvoiceCustomizeInitialValues(); + + return ( + + initialValues={initialValues} + validationSchema={InvoiceCustomizeSchema} + onSubmit={handleFormSubmit} + > + + + + + + + + + + + + + + asdfasdfdsaf #3 + + + ); +} + +const withFormikProps =

( + Component: React.ComponentType

, +) => { + return (props: Omit) => { + const { values } = useFormikContext(); + + return ; + }; +}; + +export const InvoicePaperTemplateFormConnected = + R.compose(withFormikProps)(InvoicePaperTemplate); diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeDrawer.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeDrawer.tsx index 167022bec..7c6ae6589 100644 --- a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeDrawer.tsx +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeDrawer.tsx @@ -4,9 +4,7 @@ import * as R from 'ramda'; import { Drawer, DrawerSuspense } from '@/components'; import withDrawers from '@/containers/Drawer/withDrawers'; -const InvoiceCustomize = React.lazy( - () => import('./InvoiceCustomize'), -); +const InvoiceCustomize = React.lazy(() => import('./InvoiceCustomize')); /** * Invoice customize drawer. @@ -16,10 +14,10 @@ function InvoiceCustomizeDrawerRoot({ name, // #withDrawer isOpen, - payload: {}, + payload, }) { return ( - + diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeForm.schema.ts b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeForm.schema.ts new file mode 100644 index 000000000..e972c3407 --- /dev/null +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeForm.schema.ts @@ -0,0 +1,5 @@ +import * as Yup from 'yup'; + +export const InvoiceCustomizeSchema = Yup.object().shape({ + templateName: Yup.string().required('Template Name is required'), +}); diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeGeneralFields.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeGeneralFields.tsx index 39c0a3c3f..c9f6d1827 100644 --- a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeGeneralFields.tsx +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCustomizeGeneralFields.tsx @@ -1,61 +1,84 @@ // @ts-nocheck import { Classes, Text } from '@blueprintjs/core'; -import { FFormGroup, FSwitch, Group, Stack } from '@/components'; +import { + FFormGroup, + FieldRequiredHint, + FInputGroup, + FSwitch, + Group, + Stack, +} from '@/components'; import { FColorInput } from '@/components/Forms/FColorInput'; import { CreditCardIcon } from '@/icons/CreditCardIcon'; +import { Overlay } from './Overlay'; +import { useIsTemplateNamedFilled } from './utils'; export function InvoiceCustomizeGeneralField() { + const isTemplateNameFilled = useIsTemplateNamedFilled(); + return (

General Branding

- Set your invoice details to be automatically applied every time
you + Set your invoice details to be automatically applied every timeyou create a new invoice.

- - - } + fastField + style={{ marginBottom: 10 }} + > + + + + + + - + > + + - - - + > + + - - - - + + + + - + + ); } diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCutomizeContentFields.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCutomizeContentFields.tsx index 98c4cbfe9..2bb666d80 100644 --- a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCutomizeContentFields.tsx +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/InvoiceCutomizeContentFields.tsx @@ -16,7 +16,7 @@ export function InvoiceCustomizeContentFields() {

General Branding

- Set your invoice details to be automatically applied every time
you + Set your invoice details to be automatically applied every timeyou create a new invoice.

diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/Overlay.module.scss b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/Overlay.module.scss new file mode 100644 index 000000000..dd9ece2b3 --- /dev/null +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/Overlay.module.scss @@ -0,0 +1,19 @@ + + +.root { + position: relative; + + &.visible::before{ + background: rgba(255, 255, 255, 0.75); + z-index: 2; + } + &::before{ + content: ""; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + z-index: -1000; + } +} \ No newline at end of file diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/Overlay.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/Overlay.tsx new file mode 100644 index 000000000..eceb79424 --- /dev/null +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/Overlay.tsx @@ -0,0 +1,20 @@ +import clsx from 'classnames'; +import { Box } from '@/components'; +import styles from './Overlay.module.scss'; + +export interface OverlayProps { + visible?: boolean; + children?: React.ReactNode; +} + +export function Overlay({ children, visible }: OverlayProps) { + return ( + + {children} + + ); +} diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/constants.ts b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/constants.ts index ac4a03dae..33b739dc5 100644 --- a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/constants.ts +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/constants.ts @@ -1,4 +1,6 @@ export const initialValues = { + templateName: '', + // Colors primaryColor: '#2c3dd8', secondaryColor: '#2c3dd8', diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/types.ts b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/types.ts index 6985bafb4..3e972b020 100644 --- a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/types.ts +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/types.ts @@ -1,4 +1,6 @@ export interface InvoiceCustomizeValues { + templateName: string; + // Colors primaryColor?: string; secondaryColor?: string; diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/utils.ts b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/utils.ts index a063b9ee2..f3fcd8385 100644 --- a/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/utils.ts +++ b/packages/webapp/src/containers/Sales/Invoices/InvoiceCustomize/utils.ts @@ -1,14 +1,19 @@ import { omit } from 'lodash'; +import { useFormikContext } from 'formik'; import { InvoiceCustomizeValues } from './types'; -import { CreatePdfTemplateValues, EditPdfTemplateValues } from '@/hooks/query/pdf-templates'; +import { + CreatePdfTemplateValues, + EditPdfTemplateValues, +} from '@/hooks/query/pdf-templates'; +import { useBrandingTemplateBoot } from '../BrandingTemplates/BrandingTemplateBoot'; +import { transformToForm } from '@/utils'; +import { initialValues } from './constants'; export const transformToEditRequest = ( values: InvoiceCustomizeValues, - templateId: number, ): EditPdfTemplateValues => { return { - templateId, - templateName: 'Template Name', + templateName: values.templateName, attributes: omit(values, ['templateName']), }; }; @@ -18,7 +23,29 @@ export const transformToNewRequest = ( ): CreatePdfTemplateValues => { return { resource: 'SaleInvoice', - templateName: 'Template Name', + templateName: values.templateName, attributes: omit(values, ['templateName']), }; }; + +export const useIsTemplateNamedFilled = () => { + const { values } = useFormikContext(); + + return values.templateName && values.templateName?.length >= 4; +}; + +export const useInvoiceCustomizeInitialValues = (): InvoiceCustomizeValues => { + const { pdfTemplate } = useBrandingTemplateBoot(); + + const defaultPdfTemplate = { + templateName: pdfTemplate?.templateName, + ...pdfTemplate?.attributes, + }; + return { + ...initialValues, + ...(transformToForm( + defaultPdfTemplate, + initialValues, + ) as InvoiceCustomizeValues), + }; +}; diff --git a/packages/webapp/src/containers/Sales/Invoices/InvoicesLanding/InvoicesActionsBar.tsx b/packages/webapp/src/containers/Sales/Invoices/InvoicesLanding/InvoicesActionsBar.tsx index de71f269c..bf8fe5bba 100644 --- a/packages/webapp/src/containers/Sales/Invoices/InvoicesLanding/InvoicesActionsBar.tsx +++ b/packages/webapp/src/containers/Sales/Invoices/InvoicesLanding/InvoicesActionsBar.tsx @@ -190,7 +190,7 @@ function InvoiceActionsBar({ } diff --git a/packages/webapp/src/hooks/query/pdf-templates.ts b/packages/webapp/src/hooks/query/pdf-templates.ts index d01673500..0e03aa81b 100644 --- a/packages/webapp/src/hooks/query/pdf-templates.ts +++ b/packages/webapp/src/hooks/query/pdf-templates.ts @@ -6,8 +6,12 @@ import { UseQueryOptions, UseMutationResult, UseQueryResult, + useQueryClient, } from 'react-query'; import useApiRequest from '../useRequest'; +import { transformToCamelCase, transfromToSnakeCase } from '@/utils'; + +const PdfTemplatesQueryKey = 'PdfTemplate'; export interface CreatePdfTemplateValues { templateName: string; @@ -18,7 +22,6 @@ export interface CreatePdfTemplateValues { export interface CreatePdfTemplateResponse {} export interface EditPdfTemplateValues { - templateId: string | number; templateName: string; attributes: Record; } @@ -33,7 +36,14 @@ export interface DeletePdfTemplateResponse {} export interface GetPdfTemplateValues {} -export interface GetPdfTemplateResponse {} +export interface GetPdfTemplateResponse { + templateName: string; + attributes: Record; + predefined: boolean; + default: boolean; + createdAt: string; + updatedAt: string | null; +} export interface GetPdfTemplatesValues {} @@ -52,10 +62,18 @@ export const useCreatePdfTemplate = ( CreatePdfTemplateValues > => { const apiRequest = useApiRequest(); + const queryClient = useQueryClient(); return useMutation( (values) => - apiRequest.post('/pdf-templates', values).then((res) => res.data), - options, + apiRequest + .post('/pdf-templates', transfromToSnakeCase(values)) + .then((res) => res.data), + { + onSuccess: () => { + queryClient.invalidateQueries([PdfTemplatesQueryKey]); + }, + ...options, + }, ); }; @@ -71,6 +89,7 @@ export const useEditPdfTemplate = ( Error, { templateId: number; values: EditPdfTemplateValues } > => { + const queryClient = useQueryClient(); const apiRequest = useApiRequest(); return useMutation< EditPdfTemplateResponse, @@ -79,9 +98,14 @@ export const useEditPdfTemplate = ( >( ({ templateId, values }) => apiRequest - .put(`/pdf-templates/${templateId}`, values) + .put(`/pdf-templates/${templateId}`, transfromToSnakeCase(values)) .then((res) => res.data), - options, + { + onSuccess: () => { + queryClient.invalidateQueries([PdfTemplatesQueryKey]); + }, + ...options, + }, ); }; @@ -98,10 +122,16 @@ export const useDeletePdfTemplate = ( { templateId: number } > => { const apiRequest = useApiRequest(); + const queryClient = useQueryClient(); return useMutation( ({ templateId }) => apiRequest.delete(`/pdf-templates/${templateId}`).then((res) => res.data), - options, + { + onSuccess: () => { + queryClient.invalidateQueries([PdfTemplatesQueryKey]); + }, + ...options, + }, ); }; @@ -112,9 +142,11 @@ export const useGetPdfTemplate = ( ): UseQueryResult => { const apiRequest = useApiRequest(); return useQuery( - ['pdfTemplate', templateId], + [PdfTemplatesQueryKey, templateId], () => - apiRequest.get(`/pdf-templates/${templateId}`).then((res) => res.data), + apiRequest + .get(`/pdf-templates/${templateId}`) + .then((res) => transformToCamelCase(res.data)), options, ); }; @@ -125,7 +157,7 @@ export const useGetPdfTemplates = ( ): UseQueryResult => { const apiRequest = useApiRequest(); return useQuery( - 'pdfTemplates', + PdfTemplatesQueryKey, () => apiRequest.get('/pdf-templates').then((res) => res.data), options, ); diff --git a/packages/webapp/src/hooks/state/dashboard.tsx b/packages/webapp/src/hooks/state/dashboard.tsx index 74cdf295e..6f424191b 100644 --- a/packages/webapp/src/hooks/state/dashboard.tsx +++ b/packages/webapp/src/hooks/state/dashboard.tsx @@ -10,6 +10,8 @@ import { closeSidebarSubmenu, openDialog, closeDialog, + openDrawer, + closeDrawer, } from '@/store/dashboard/dashboard.actions'; export const useDispatchAction = (action) => { @@ -77,3 +79,10 @@ export const useDialogActions = () => { closeDialog: useDispatchAction(closeDialog), }; }; + +export const useDrawerActions = () => { + return { + openDrawer: useDispatchAction(openDrawer), + closeDrawer: useDispatchAction(closeDrawer), + }; +};