From 6f2a456a56838a02a8ba86b8660e3cb43eb22a16 Mon Sep 17 00:00:00 2001
From: elforjani13 <39470382+elforjani13@users.noreply.github.com>
Date: Thu, 30 Jun 2022 22:03:50 +0200
Subject: [PATCH] feat: add expense form.
---
.../ExpenseFormDialog/ExpenseForm.schema.tsx | 21 +++
.../ExpenseFormDialog/ExpenseForm.tsx | 64 ++++++++
.../ExpenseFormChargeFields.tsx | 55 +++++++
.../ExpenseFormDialog/ExpenseFormContent.tsx | 17 +++
.../ExpenseFormDialogContent.tsx | 19 +++
.../ExpenseFormDialog/ExpenseFormFields.tsx | 141 ++++++++++++++++++
.../ExpenseFormDialog/ExpenseFormProvider.tsx | 30 ++++
.../ExpneseFormFloatingActions.tsx | 44 ++++++
.../containers/ExpenseFormDialog/index.tsx | 55 +++++++
9 files changed, 446 insertions(+)
create mode 100644 src/containers/Projects/containers/ExpenseFormDialog/ExpenseForm.schema.tsx
create mode 100644 src/containers/Projects/containers/ExpenseFormDialog/ExpenseForm.tsx
create mode 100644 src/containers/Projects/containers/ExpenseFormDialog/ExpenseFormChargeFields.tsx
create mode 100644 src/containers/Projects/containers/ExpenseFormDialog/ExpenseFormContent.tsx
create mode 100644 src/containers/Projects/containers/ExpenseFormDialog/ExpenseFormDialogContent.tsx
create mode 100644 src/containers/Projects/containers/ExpenseFormDialog/ExpenseFormFields.tsx
create mode 100644 src/containers/Projects/containers/ExpenseFormDialog/ExpenseFormProvider.tsx
create mode 100644 src/containers/Projects/containers/ExpenseFormDialog/ExpneseFormFloatingActions.tsx
create mode 100644 src/containers/Projects/containers/ExpenseFormDialog/index.tsx
diff --git a/src/containers/Projects/containers/ExpenseFormDialog/ExpenseForm.schema.tsx b/src/containers/Projects/containers/ExpenseFormDialog/ExpenseForm.schema.tsx
new file mode 100644
index 000000000..c2bc038cc
--- /dev/null
+++ b/src/containers/Projects/containers/ExpenseFormDialog/ExpenseForm.schema.tsx
@@ -0,0 +1,21 @@
+import * as Yup from 'yup';
+import intl from 'react-intl-universal';
+import { DATATYPES_LENGTH } from 'common/dataTypes';
+
+const Schema = Yup.object().shape({
+ expenseName: Yup.string().label(
+ intl.get('expense.schema.label.expense_name'),
+ ),
+ estimatedExpense: Yup.number().label(
+ intl.get('expense.schema.label.estimated_expense'),
+ ),
+ expemseDate: Yup.date(),
+ expenseQuantity: Yup.number().label(intl.get('expense.schema.label.quantity')),
+ expenseUnitPrice: Yup.number().label(
+ intl.get('expense.schema.label.unitPrice'),
+ ),
+ expenseTotal: Yup.number(),
+ expenseCharge: Yup.string(),
+});
+
+export const CreateExpenseFormSchema = Schema;
diff --git a/src/containers/Projects/containers/ExpenseFormDialog/ExpenseForm.tsx b/src/containers/Projects/containers/ExpenseFormDialog/ExpenseForm.tsx
new file mode 100644
index 000000000..6bcf46531
--- /dev/null
+++ b/src/containers/Projects/containers/ExpenseFormDialog/ExpenseForm.tsx
@@ -0,0 +1,64 @@
+import React from 'react';
+import moment from 'moment';
+import intl from 'react-intl-universal';
+import { Formik } from 'formik';
+import { AppToaster } from 'components';
+import { CreateExpenseFormSchema } from './ExpenseForm.schema';
+import ExpenseFormContent from './ExpenseFormContent';
+import { useExpenseFormContext } from './ExpenseFormProvider';
+import withDialogActions from 'containers/Dialog/withDialogActions';
+
+import { compose } from 'utils';
+
+const defaultInitialValues = {
+ expenseName: '',
+ estimatedExpense: '',
+ expemseDate: moment(new Date()).format('YYYY-MM-DD'),
+ expenseUnitPrice: '',
+ expenseQuantity: 1,
+ expenseCharge: '% markup',
+ percentage: '',
+ expenseTotal: '',
+};
+
+/**
+ * Expense form.
+ * @returns
+ */
+function ExpenseForm({
+ //#withDialogActions
+ closeDialog,
+}) {
+ const initialValues = {
+ ...defaultInitialValues,
+ };
+
+ // Handles the form submit.
+ const handleFormSubmit = (values, { setSubmitting, setErrors }) => {
+ const form = {};
+
+ // Handle request response success.
+ const onSuccess = (response) => {
+ AppToaster.show({});
+ };
+
+ // Handle request response errors.
+ const onError = ({
+ response: {
+ data: { errors },
+ },
+ }) => {
+ setSubmitting(false);
+ };
+ };
+ return (
+
+ );
+}
+
+export default compose(withDialogActions)(ExpenseForm);
diff --git a/src/containers/Projects/containers/ExpenseFormDialog/ExpenseFormChargeFields.tsx b/src/containers/Projects/containers/ExpenseFormDialog/ExpenseFormChargeFields.tsx
new file mode 100644
index 000000000..9f8272592
--- /dev/null
+++ b/src/containers/Projects/containers/ExpenseFormDialog/ExpenseFormChargeFields.tsx
@@ -0,0 +1,55 @@
+//@ts-nocheck
+import React from 'react';
+import intl from 'react-intl-universal';
+import { Classes, ControlGroup } from '@blueprintjs/core';
+import { FFormGroup, FInputGroup, Choose } from 'components';
+import { useFormikContext } from 'formik';
+
+function PercentageFormField() {
+ return (
+
+
+
+ );
+}
+
+function CustomPirceField() {
+ return (
+
+
+
+
+
+
+
+
+ );
+}
+
+/**
+ * Expense form charge fields.
+ * @returns
+ */
+export default function ExpenseFormChargeFields() {
+ const { values } = useFormikContext();
+
+ return (
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/containers/Projects/containers/ExpenseFormDialog/ExpenseFormContent.tsx b/src/containers/Projects/containers/ExpenseFormDialog/ExpenseFormContent.tsx
new file mode 100644
index 000000000..a73c7d1dd
--- /dev/null
+++ b/src/containers/Projects/containers/ExpenseFormDialog/ExpenseFormContent.tsx
@@ -0,0 +1,17 @@
+import React from 'react';
+import { Form } from 'formik';
+import ExpenseFormFields from './ExpenseFormFields';
+import ExpneseFormFloatingActions from './ExpneseFormFloatingActions';
+
+/**
+ * Expense form content.
+ * @returns
+ */
+export default function ExpenseFormContent() {
+ return (
+
+ );
+}
diff --git a/src/containers/Projects/containers/ExpenseFormDialog/ExpenseFormDialogContent.tsx b/src/containers/Projects/containers/ExpenseFormDialog/ExpenseFormDialogContent.tsx
new file mode 100644
index 000000000..12a9f01b9
--- /dev/null
+++ b/src/containers/Projects/containers/ExpenseFormDialog/ExpenseFormDialogContent.tsx
@@ -0,0 +1,19 @@
+import React from 'react';
+import { ExpenseFormProvider } from './ExpenseFormProvider';
+import ExpenseForm from './ExpenseForm';
+
+/**
+ * Expense form dialog content.
+ * @returns
+ */
+export default function ExpenseFormDialogContent({
+ // #ownProps
+ dialogName,
+ expense,
+}) {
+ return (
+
+
+
+ );
+}
diff --git a/src/containers/Projects/containers/ExpenseFormDialog/ExpenseFormFields.tsx b/src/containers/Projects/containers/ExpenseFormDialog/ExpenseFormFields.tsx
new file mode 100644
index 000000000..07901a049
--- /dev/null
+++ b/src/containers/Projects/containers/ExpenseFormDialog/ExpenseFormFields.tsx
@@ -0,0 +1,141 @@
+//@ts-nocheck
+import React from 'react';
+import styled from 'styled-components';
+import intl from 'react-intl-universal';
+import { Classes, Position, ControlGroup } from '@blueprintjs/core';
+import { CLASSES } from 'common/classes';
+import classNames from 'classnames';
+import {
+ FFormGroup,
+ FInputGroup,
+ FDateInput,
+ FormattedMessage as T,
+} from 'components';
+import { ExpenseSelect } from '../../components';
+import ExpenseFormChargeFields from './ExpenseFormChargeFields';
+import { momentFormatter } from 'utils';
+import { useExpenseFormContext } from './ExpenseFormProvider';
+import { ChargeSelect } from '../../components';
+import { expenseChargeOption } from 'common/modalChargeOptions';
+
+/**
+ * Expense form fields.
+ * @returns
+ */
+export default function ExpenseFormFields() {
+ return (
+
+ {/*------------ Expense Name -----------*/}
+
+
+
+ {/*------------ Track to Expense -----------*/}
+
+
+
+
+ {/*------------ Extimated Date -----------*/}
+
+ date.toLocaleString()}
+ popoverProps={{
+ position: Position.BOTTOM,
+ minimal: true,
+ }}
+ />
+
+ {/*------------ Quantity -----------*/}
+
+
+
+
+ Cost to you
+ {/*------------ Unit Price -----------*/}
+
+
+
+
+
+
+
+
+
+ What you'll charge
+ {/*------------ Charge -----------*/}
+ }
+ className={classNames('form-group--select-list', Classes.FILL)}
+ >
+
+
+
+ {/*------------ Charge Fields -----------*/}
+
+
+ {/*------------ Total -----------*/}
+
+
+
+
+ 0.00
+
+
+ );
+}
+
+const MetaLineLabel = styled.div`
+ font-size: 14px;
+ line-height: 1.5rem;
+ font-weight: 500;
+ margin-bottom: 8px;
+`;
+
+const ExpenseTotalBase = styled.div`
+ display: block;
+ text-align: right;
+`;
+
+const ExpenseTotalLabel = styled.div`
+ font-size: 14px;
+ line-height: 1.5rem;
+ opacity: 0.75;
+`;
+
+const ExpenseTotal = styled.div`
+ font-size: 15px;
+ font-weight: 700;
+ padding-left: 14px;
+ line-height: 2rem;
+`;
diff --git a/src/containers/Projects/containers/ExpenseFormDialog/ExpenseFormProvider.tsx b/src/containers/Projects/containers/ExpenseFormDialog/ExpenseFormProvider.tsx
new file mode 100644
index 000000000..eea3375a4
--- /dev/null
+++ b/src/containers/Projects/containers/ExpenseFormDialog/ExpenseFormProvider.tsx
@@ -0,0 +1,30 @@
+//@ts-nocheck
+import React from 'react';
+import { DialogContent } from 'components';
+
+const ExpenseFormContext = React.createContext();
+
+/**
+ * Expense form provider.
+ * @returns
+ */
+function ExpenseFormProvider({
+ //#OwnProps
+ dialogName,
+ expenseId,
+ ...props
+}) {
+ // state provider.
+ const provider = {
+ dialogName,
+ };
+
+ return (
+
+
+
+ );
+}
+
+const useExpenseFormContext = () => React.useContext(ExpenseFormContext);
+export { ExpenseFormProvider, useExpenseFormContext };
diff --git a/src/containers/Projects/containers/ExpenseFormDialog/ExpneseFormFloatingActions.tsx b/src/containers/Projects/containers/ExpenseFormDialog/ExpneseFormFloatingActions.tsx
new file mode 100644
index 000000000..ad056b14b
--- /dev/null
+++ b/src/containers/Projects/containers/ExpenseFormDialog/ExpneseFormFloatingActions.tsx
@@ -0,0 +1,44 @@
+//@ts-nocheck
+import React from 'react';
+import { useFormikContext } from 'formik';
+import { Intent, Button, Classes } from '@blueprintjs/core';
+import { FormattedMessage as T } from 'components';
+import { useExpenseFormContext } from './ExpenseFormProvider';
+import withDialogActions from 'containers/Dialog/withDialogActions';
+import { compose } from 'utils';
+
+function ExpneseFormFloatingActions({
+ // #withDialogActions
+ closeDialog,
+}) {
+ // Formik context.
+ const { isSubmitting } = useFormikContext();
+
+ // expense form dialog context.
+ const { dialogName } = useExpenseFormContext();
+
+ // Handle close button click.
+ const handleCancelBtnClick = () => {
+ closeDialog(dialogName);
+ };
+
+ return (
+
+ );
+}
+
+export default compose(withDialogActions)(ExpneseFormFloatingActions);
diff --git a/src/containers/Projects/containers/ExpenseFormDialog/index.tsx b/src/containers/Projects/containers/ExpenseFormDialog/index.tsx
new file mode 100644
index 000000000..fbcd6d079
--- /dev/null
+++ b/src/containers/Projects/containers/ExpenseFormDialog/index.tsx
@@ -0,0 +1,55 @@
+import React from 'react';
+import styled from 'styled-components';
+import { Dialog, DialogSuspense, FormattedMessage as T } from 'components';
+import withDialogRedux from 'components/DialogReduxConnect';
+import { compose } from 'utils';
+
+const ExpenseFormeDialogContent = React.lazy(
+ () => import('./ExpenseFormDialogContent'),
+);
+
+/**
+ * Expense form dialog.
+ * @returns
+ */
+function ExpenseFormDialog({
+ dialogName,
+ payload: { projectId = null },
+ isOpen,
+}) {
+ return (
+ }
+ isOpen={isOpen}
+ autoFocus={true}
+ canEscapeKeyClose={true}
+ style={{ width: '400px' }}
+ >
+
+
+
+
+ );
+}
+
+export default compose(withDialogRedux())(ExpenseFormDialog);
+
+const ExpenseFormDialogRoot = styled(Dialog)`
+ .bp3-dialog-body {
+ .bp3-form-group {
+ margin-bottom: 15px;
+
+ label.bp3-label {
+ margin-bottom: 3px;
+ font-size: 13px;
+ }
+ }
+ }
+ .bp3-dialog-footer {
+ padding-top: 10px;
+ }
+`;