diff --git a/packages/webapp/src/constants/preferencesMenu.tsx b/packages/webapp/src/constants/preferencesMenu.tsx
index f90c7ed04..562cce1b1 100644
--- a/packages/webapp/src/constants/preferencesMenu.tsx
+++ b/packages/webapp/src/constants/preferencesMenu.tsx
@@ -12,6 +12,10 @@ export default [
text: ,
href: '/preferences/users',
},
+ {
+ text: 'Invoices',
+ href: '/preferences/invoices',
+ },
{
text: ,
href: '/preferences/currencies',
diff --git a/packages/webapp/src/containers/Preferences/CreditNotes/PreferencesCreditNotes.tsx b/packages/webapp/src/containers/Preferences/CreditNotes/PreferencesCreditNotes.tsx
new file mode 100644
index 000000000..ee1753398
--- /dev/null
+++ b/packages/webapp/src/containers/Preferences/CreditNotes/PreferencesCreditNotes.tsx
@@ -0,0 +1,14 @@
+// @ts-nocheck
+import { PreferencesCreditNotesBoot } from './PreferencesCreditNotesFormBoot';
+import PreferencesInvoiceFormPage from './PreferencesCreditNotesFormPage';
+
+/**
+ * items preferences.
+ */
+export default function PreferencesCreditNotes() {
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/containers/Preferences/CreditNotes/PreferencesCreditNotesForm.schema.ts b/packages/webapp/src/containers/Preferences/CreditNotes/PreferencesCreditNotesForm.schema.ts
new file mode 100644
index 000000000..b6cf3eab6
--- /dev/null
+++ b/packages/webapp/src/containers/Preferences/CreditNotes/PreferencesCreditNotesForm.schema.ts
@@ -0,0 +1,9 @@
+// @ts-nocheck
+import * as Yup from 'yup';
+
+const Schema = Yup.object().shape({
+ termsConditions: Yup.string().optional(),
+ customerNotes: Yup.string().optional(),
+});
+
+export const PreferencesEstimatesFormSchema = Schema;
diff --git a/packages/webapp/src/containers/Preferences/CreditNotes/PreferencesCreditNotesForm.tsx b/packages/webapp/src/containers/Preferences/CreditNotes/PreferencesCreditNotesForm.tsx
new file mode 100644
index 000000000..17fc18c0d
--- /dev/null
+++ b/packages/webapp/src/containers/Preferences/CreditNotes/PreferencesCreditNotesForm.tsx
@@ -0,0 +1,80 @@
+// @ts-nocheck
+import styled from 'styled-components';
+import { Form } from 'formik';
+import { Button, Intent } from '@blueprintjs/core';
+import { useHistory } from 'react-router-dom';
+
+import {
+ FieldRequiredHint,
+ FormattedMessage as T,
+ FFormGroup,
+ FTextArea,
+} from '@/components';
+
+/**
+ * Preferences estimates form.
+ */
+export function PreferencesCreditNotesForm({ isSubmitting }) {
+ const history = useHistory();
+
+ // Handle close click.
+ const handleCloseClick = () => {
+ history.go(-1);
+ };
+
+ return (
+
+ );
+}
+
+const CardFooterActions = styled.div`
+ padding-top: 16px;
+ border-top: 1px solid #e0e7ea;
+ margin-top: 30px;
+
+ .bp4-button {
+ min-width: 70px;
+
+ + .bp4-button {
+ margin-left: 10px;
+ }
+ }
+`;
diff --git a/packages/webapp/src/containers/Preferences/CreditNotes/PreferencesCreditNotesFormBoot.tsx b/packages/webapp/src/containers/Preferences/CreditNotes/PreferencesCreditNotesFormBoot.tsx
new file mode 100644
index 000000000..c416f69c4
--- /dev/null
+++ b/packages/webapp/src/containers/Preferences/CreditNotes/PreferencesCreditNotesFormBoot.tsx
@@ -0,0 +1,41 @@
+// @ts-nocheck
+import React from 'react';
+import classNames from 'classnames';
+import { CLASSES } from '@/constants/classes';
+import { useSettings } from '@/hooks/query';
+import PreferencesPageLoader from '../PreferencesPageLoader';
+
+const PreferencesCreditNotesFormContext = React.createContext();
+
+function PreferencesCreditNotesBoot({ ...props }) {
+ // Fetches organization settings.
+ const { isLoading: isSettingsLoading } = useSettings();
+
+ // Provider state.
+ const provider = {
+ organization: {},
+ };
+
+ // Detarmines whether if any query is loading.
+ const isLoading = isSettingsLoading;
+
+ return (
+
+ {isLoading ? (
+
+ ) : (
+
+ )}
+
+ );
+}
+
+const usePreferencesCreditNotesFormContext = () =>
+ React.useContext(PreferencesCreditNotesFormContext);
+
+export { PreferencesCreditNotesBoot, usePreferencesCreditNotesFormContext };
diff --git a/packages/webapp/src/containers/Preferences/CreditNotes/PreferencesCreditNotesFormPage.tsx b/packages/webapp/src/containers/Preferences/CreditNotes/PreferencesCreditNotesFormPage.tsx
new file mode 100644
index 000000000..045ffbbc5
--- /dev/null
+++ b/packages/webapp/src/containers/Preferences/CreditNotes/PreferencesCreditNotesFormPage.tsx
@@ -0,0 +1,69 @@
+// @ts-nocheck
+import React, { useEffect } from 'react';
+import intl from 'react-intl-universal';
+import { Formik } from 'formik';
+import { Intent } from '@blueprintjs/core';
+
+import { AppToaster } from '@/components';
+import { PreferencesCreditNotesFormSchema } from './PreferencesCreditNotesForm.schema';
+import { usePreferencesInvoiceFormContext } from './PreferencesCreditNotesFormBoot';
+import { PreferencesCreditNotesForm } from './PreferencesCreditNotesForm';
+import withDashboardActions from '@/containers/Dashboard/withDashboardActions';
+
+import { compose, transformToForm } from '@/utils';
+
+const defaultValues = {
+ termsConditions: '',
+ customerNotes: '',
+};
+
+/**
+ * Preferences - .
+ */
+function PreferencesCreditNotesFormPageRoot({
+ // #withDashboardActions
+ changePreferencesPageTitle,
+}) {
+ const { organization } = usePreferencesInvoiceFormContext();
+
+ useEffect(() => {
+ changePreferencesPageTitle(intl.get('preferences.estimates'));
+ }, [changePreferencesPageTitle]);
+
+ // Initial values.
+ const initialValues = {
+ ...defaultValues,
+ ...transformToForm(organization.metadata, defaultValues),
+ };
+ // Handle the form submit.
+ const handleFormSubmit = (values, { setSubmitting }) => {
+ // Handle request success.
+ const onSuccess = (response) => {
+ AppToaster.show({
+ message: intl.get('preferences.estimates.success_message'),
+ intent: Intent.SUCCESS,
+ });
+ setSubmitting(false);
+ };
+ // Handle request error.
+ const onError = () => {
+ setSubmitting(false);
+ };
+ // updateOrganization({ ...values })
+ // .then(onSuccess)
+ // .catch(onError);
+ };
+
+ return (
+
+ );
+}
+
+export const PreferencesCreditNotesFormPage = compose(withDashboardActions)(
+ PreferencesCreditNotesFormPageRoot,
+);
diff --git a/packages/webapp/src/containers/Preferences/Estimates/PreferencesEstimates.tsx b/packages/webapp/src/containers/Preferences/Estimates/PreferencesEstimates.tsx
new file mode 100644
index 000000000..2b5af6bdf
--- /dev/null
+++ b/packages/webapp/src/containers/Preferences/Estimates/PreferencesEstimates.tsx
@@ -0,0 +1,14 @@
+// @ts-nocheck
+import { PreferencesEstimatesBoot } from './PreferencesEstimatesFormBoot';
+import PreferencesInvoiceFormPage from './PreferencesEstimatesFormPage';
+
+/**
+ * items preferences.
+ */
+export default function PreferencesEstimates() {
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/containers/Preferences/Estimates/PreferencesEstimatesForm.schema.ts b/packages/webapp/src/containers/Preferences/Estimates/PreferencesEstimatesForm.schema.ts
new file mode 100644
index 000000000..b6cf3eab6
--- /dev/null
+++ b/packages/webapp/src/containers/Preferences/Estimates/PreferencesEstimatesForm.schema.ts
@@ -0,0 +1,9 @@
+// @ts-nocheck
+import * as Yup from 'yup';
+
+const Schema = Yup.object().shape({
+ termsConditions: Yup.string().optional(),
+ customerNotes: Yup.string().optional(),
+});
+
+export const PreferencesEstimatesFormSchema = Schema;
diff --git a/packages/webapp/src/containers/Preferences/Estimates/PreferencesEstimatesForm.tsx b/packages/webapp/src/containers/Preferences/Estimates/PreferencesEstimatesForm.tsx
new file mode 100644
index 000000000..426797f4d
--- /dev/null
+++ b/packages/webapp/src/containers/Preferences/Estimates/PreferencesEstimatesForm.tsx
@@ -0,0 +1,80 @@
+// @ts-nocheck
+import styled from 'styled-components';
+import { Form } from 'formik';
+import { Button, Intent } from '@blueprintjs/core';
+import { useHistory } from 'react-router-dom';
+
+import {
+ FieldRequiredHint,
+ FormattedMessage as T,
+ FFormGroup,
+ FTextArea,
+} from '@/components';
+
+/**
+ * Preferences estimates form.
+ */
+export function PreferencesEstimatesForm({ isSubmitting }) {
+ const history = useHistory();
+
+ // Handle close click.
+ const handleCloseClick = () => {
+ history.go(-1);
+ };
+
+ return (
+
+ );
+}
+
+const CardFooterActions = styled.div`
+ padding-top: 16px;
+ border-top: 1px solid #e0e7ea;
+ margin-top: 30px;
+
+ .bp4-button {
+ min-width: 70px;
+
+ + .bp4-button {
+ margin-left: 10px;
+ }
+ }
+`;
diff --git a/packages/webapp/src/containers/Preferences/Estimates/PreferencesEstimatesFormBoot.tsx b/packages/webapp/src/containers/Preferences/Estimates/PreferencesEstimatesFormBoot.tsx
new file mode 100644
index 000000000..e444c5998
--- /dev/null
+++ b/packages/webapp/src/containers/Preferences/Estimates/PreferencesEstimatesFormBoot.tsx
@@ -0,0 +1,41 @@
+// @ts-nocheck
+import React from 'react';
+import classNames from 'classnames';
+import { CLASSES } from '@/constants/classes';
+import { useSettings } from '@/hooks/query';
+import PreferencesPageLoader from '../PreferencesPageLoader';
+
+const PreferencesEstimatesFormContext = React.createContext();
+
+function PreferencesEstimatesBoot({ ...props }) {
+ // Fetches organization settings.
+ const { isLoading: isSettingsLoading } = useSettings();
+
+ // Provider state.
+ const provider = {
+ organization: {},
+ };
+
+ // Detarmines whether if any query is loading.
+ const isLoading = isSettingsLoading;
+
+ return (
+
+ {isLoading ? (
+
+ ) : (
+
+ )}
+
+ );
+}
+
+const usePreferencesEstimatesFormContext = () =>
+ React.useContext(PreferencesEstimatesFormContext);
+
+export { PreferencesEstimatesBoot, usePreferencesEstimatesFormContext };
diff --git a/packages/webapp/src/containers/Preferences/Estimates/PreferencesEstimatesFormPage.tsx b/packages/webapp/src/containers/Preferences/Estimates/PreferencesEstimatesFormPage.tsx
new file mode 100644
index 000000000..b74279741
--- /dev/null
+++ b/packages/webapp/src/containers/Preferences/Estimates/PreferencesEstimatesFormPage.tsx
@@ -0,0 +1,69 @@
+// @ts-nocheck
+import React, { useEffect } from 'react';
+import intl from 'react-intl-universal';
+import { Formik } from 'formik';
+import { Intent } from '@blueprintjs/core';
+
+import { AppToaster } from '@/components';
+import { PreferencesEstimatesFormSchema } from './PreferencesEstimatesForm.schema';
+import { usePreferencesInvoiceFormContext } from './PreferencesEstimatesFormBoot';
+import { PreferencesEstimatesForm } from './PreferencesEstimatesForm';
+import withDashboardActions from '@/containers/Dashboard/withDashboardActions';
+
+import { compose, transformToForm } from '@/utils';
+
+const defaultValues = {
+ termsConditions: '',
+ customerNotes: '',
+};
+
+/**
+ * Preferences - .
+ */
+function PreferencesEstimatesFormPageRoot({
+ // #withDashboardActions
+ changePreferencesPageTitle,
+}) {
+ const { organization } = usePreferencesInvoiceFormContext();
+
+ useEffect(() => {
+ changePreferencesPageTitle(intl.get('preferences.estimates'));
+ }, [changePreferencesPageTitle]);
+
+ // Initial values.
+ const initialValues = {
+ ...defaultValues,
+ ...transformToForm(organization.metadata, defaultValues),
+ };
+ // Handle the form submit.
+ const handleFormSubmit = (values, { setSubmitting }) => {
+ // Handle request success.
+ const onSuccess = (response) => {
+ AppToaster.show({
+ message: intl.get('preferences.estimates.success_message'),
+ intent: Intent.SUCCESS,
+ });
+ setSubmitting(false);
+ };
+ // Handle request error.
+ const onError = () => {
+ setSubmitting(false);
+ };
+ // updateOrganization({ ...values })
+ // .then(onSuccess)
+ // .catch(onError);
+ };
+
+ return (
+
+ );
+}
+
+export const PreferencesEstimatesFormPage = compose(withDashboardActions)(
+ PreferencesEstimatesFormPageRoot,
+);
diff --git a/packages/webapp/src/containers/Preferences/Invoices/PreferencesInvoiceForm.schema.ts b/packages/webapp/src/containers/Preferences/Invoices/PreferencesInvoiceForm.schema.ts
new file mode 100644
index 000000000..be7bead85
--- /dev/null
+++ b/packages/webapp/src/containers/Preferences/Invoices/PreferencesInvoiceForm.schema.ts
@@ -0,0 +1,9 @@
+// @ts-nocheck
+import * as Yup from 'yup';
+
+const Schema = Yup.object().shape({
+ termsConditions: Yup.string().optional(),
+ customerNotes: Yup.string().optional(),
+});
+
+export const PreferencesInvoiceFormSchema = Schema;
diff --git a/packages/webapp/src/containers/Preferences/Invoices/PreferencesInvoiceFormBoot.tsx b/packages/webapp/src/containers/Preferences/Invoices/PreferencesInvoiceFormBoot.tsx
new file mode 100644
index 000000000..b4983531a
--- /dev/null
+++ b/packages/webapp/src/containers/Preferences/Invoices/PreferencesInvoiceFormBoot.tsx
@@ -0,0 +1,41 @@
+// @ts-nocheck
+import React from 'react';
+import classNames from 'classnames';
+import { CLASSES } from '@/constants/classes';
+import { useSettings } from '@/hooks/query';
+import PreferencesPageLoader from '../PreferencesPageLoader';
+
+const PreferencesInvoiceFormContext = React.createContext();
+
+function PreferencesInvoicesBoot({ ...props }) {
+ // Fetches organization settings.
+ const { isLoading: isSettingsLoading } = useSettings();
+
+ // Provider state.
+ const provider = {
+ organization: {},
+ };
+
+ // Detarmines whether if any query is loading.
+ const isLoading = isSettingsLoading;
+
+ return (
+
+ {isLoading ? (
+
+ ) : (
+
+ )}
+
+ );
+}
+
+const usePreferencesInvoiceFormContext = () =>
+ React.useContext(PreferencesInvoiceFormContext);
+
+export { PreferencesInvoicesBoot, usePreferencesInvoiceFormContext };
diff --git a/packages/webapp/src/containers/Preferences/Invoices/PreferencesInvoiceFormPage.tsx b/packages/webapp/src/containers/Preferences/Invoices/PreferencesInvoiceFormPage.tsx
new file mode 100644
index 000000000..ddf74b02f
--- /dev/null
+++ b/packages/webapp/src/containers/Preferences/Invoices/PreferencesInvoiceFormPage.tsx
@@ -0,0 +1,67 @@
+// @ts-nocheck
+import React, { useEffect } from 'react';
+import intl from 'react-intl-universal';
+import { Formik } from 'formik';
+import { Intent } from '@blueprintjs/core';
+
+import { AppToaster } from '@/components';
+import { PreferencesInvoiceFormSchema } from './PreferencesInvoiceForm.schema';
+import { usePreferencesInvoiceFormContext } from './PreferencesInvoiceFormBoot';
+import { PreferencesGeneralForm } from './PreferencesInvoicesForm';
+import withDashboardActions from '@/containers/Dashboard/withDashboardActions';
+
+import { compose, transformToForm } from '@/utils';
+
+const defaultValues = {
+ termsConditions: '',
+ customerNotes: '',
+};
+
+/**
+ * Preferences - Invoices.
+ */
+function PreferencesInvoiceFormPage({
+ // #withDashboardActions
+ changePreferencesPageTitle,
+}) {
+ const { organization } = usePreferencesInvoiceFormContext();
+
+ useEffect(() => {
+ changePreferencesPageTitle(intl.get('preferences.invoices'));
+ }, [changePreferencesPageTitle]);
+
+ // Initial values.
+ const initialValues = {
+ ...defaultValues,
+ ...transformToForm(organization.metadata, defaultValues),
+ };
+ // Handle the form submit.
+ const handleFormSubmit = (values, { setSubmitting }) => {
+ // Handle request success.
+ const onSuccess = (response) => {
+ AppToaster.show({
+ message: intl.get('preferences.invoices.success_message'),
+ intent: Intent.SUCCESS,
+ });
+ setSubmitting(false);
+ };
+ // Handle request error.
+ const onError = () => {
+ setSubmitting(false);
+ };
+ // updateOrganization({ ...values })
+ // .then(onSuccess)
+ // .catch(onError);
+ };
+
+ return (
+
+ );
+}
+
+export default compose(withDashboardActions)(PreferencesInvoiceFormPage);
diff --git a/packages/webapp/src/containers/Preferences/Invoices/PreferencesInvoices.tsx b/packages/webapp/src/containers/Preferences/Invoices/PreferencesInvoices.tsx
new file mode 100644
index 000000000..da349ea9a
--- /dev/null
+++ b/packages/webapp/src/containers/Preferences/Invoices/PreferencesInvoices.tsx
@@ -0,0 +1,14 @@
+// @ts-nocheck
+import { PreferencesInvoicesBoot } from './PreferencesInvoiceFormBoot';
+import PreferencesInvoiceFormPage from './PreferencesInvoiceFormPage';
+
+/**
+ * items preferences.
+ */
+export default function PreferencesInvoices() {
+ return (
+
+
+
+ );
+}
diff --git a/packages/webapp/src/containers/Preferences/Invoices/PreferencesInvoicesForm.tsx b/packages/webapp/src/containers/Preferences/Invoices/PreferencesInvoicesForm.tsx
new file mode 100644
index 000000000..0e2b44f51
--- /dev/null
+++ b/packages/webapp/src/containers/Preferences/Invoices/PreferencesInvoicesForm.tsx
@@ -0,0 +1,81 @@
+// @ts-nocheck
+import styled from 'styled-components';
+import { Form } from 'formik';
+import { Button, Intent } from '@blueprintjs/core';
+import { useHistory } from 'react-router-dom';
+
+import {
+ FieldRequiredHint,
+ FormattedMessage as T,
+ FFormGroup,
+ FInputGroup,
+ FTextArea,
+} from '@/components';
+
+/**
+ * Preferences general form.
+ */
+export function PreferencesGeneralForm({ isSubmitting }) {
+ const history = useHistory();
+
+ // Handle close click.
+ const handleCloseClick = () => {
+ history.go(-1);
+ };
+
+ return (
+
+ );
+}
+
+const CardFooterActions = styled.div`
+ padding-top: 16px;
+ border-top: 1px solid #e0e7ea;
+ margin-top: 30px;
+
+ .bp4-button {
+ min-width: 70px;
+
+ + .bp4-button {
+ margin-left: 10px;
+ }
+ }
+`;
diff --git a/packages/webapp/src/lang/en/index.json b/packages/webapp/src/lang/en/index.json
index 4a78b4e76..f67a6f478 100644
--- a/packages/webapp/src/lang/en/index.json
+++ b/packages/webapp/src/lang/en/index.json
@@ -2290,5 +2290,8 @@
"sidebar.new_project": "New Project",
"sidebar.new_time_entry": "New Time Entry",
"sidebar.project_profitability_summary": "Project Profitability Summary",
- "global_error.too_many_requests": "Too many requests"
+ "global_error.too_many_requests": "Too many requests",
+
+ "pref.invoices.termsConditions.field": "Terms & Conditions",
+ "pref.invoices.customerNotes.field": "Customer Notes"
}
diff --git a/packages/webapp/src/routes/preferences.tsx b/packages/webapp/src/routes/preferences.tsx
index 775efcf82..5fdcb13e6 100644
--- a/packages/webapp/src/routes/preferences.tsx
+++ b/packages/webapp/src/routes/preferences.tsx
@@ -9,6 +9,8 @@ import SMSIntegration from '../containers/Preferences/SMSIntegration';
import DefaultRoute from '../containers/Preferences/DefaultRoute';
import Warehouses from '../containers/Preferences/Warehouses';
import Branches from '../containers/Preferences/Branches';
+import Invoices from '../containers/Preferences/Invoices/PreferencesInvoices';
+
const BASE_URL = '/preferences';
@@ -23,6 +25,16 @@ export default [
component: Users,
exact: true,
},
+ {
+ path: `${BASE_URL}/invoices`,
+ component: Invoices,
+ exact: true,
+ },
+ {
+ path: `${BASE_URL}/credit-notes`,
+ component: CreditNotes,
+ exact: true,
+ },
{
path: `${BASE_URL}/roles`,
component: Roles,