From 91f69e79e57d4566d1d13d4dd550717bc88fe4c1 Mon Sep 17 00:00:00 2001 From: vchikalkin Date: Tue, 28 Mar 2023 14:49:34 +0300 Subject: [PATCH] pages: add unlimited --- .env | 3 - .../Calculation/Form/Unlimited/config.ts | 12 ++ .../Calculation/Form/Unlimited/index.jsx | 12 ++ .../web/Components/Calculation/Form/index.jsx | 30 ++-- .../Calculation/config/elements-components.ts | 1 + .../Calculation/config/elements-props.tsx | 4 + .../Calculation/config/elements-titles.ts | 1 + .../Calculation/config/elements-types.ts | 1 + .../Calculation/config/map/values.ts | 1 + apps/web/Components/Layout/Logo.jsx | 35 ++++- apps/web/Components/Layout/Page.jsx | 27 ++++ apps/web/api/core/types/calculate.ts | 5 + apps/web/api/user/tools.ts | 9 +- apps/web/config/default-options.ts | 1 + apps/web/config/default-statuses.ts | 1 + apps/web/config/default-values.ts | 1 + apps/web/config/schema/env.js | 1 - apps/web/config/schema/runtime-config.js | 1 - apps/web/config/schema/values.ts | 1 + apps/web/config/users.js | 3 + apps/web/graphql/crm.query.graphql | 9 ++ apps/web/graphql/crm.types.ts | 8 + apps/web/pages/_document.jsx | 2 +- apps/web/pages/index.jsx | 141 ++++++++---------- apps/web/pages/unlimited.jsx | 37 +++++ .../process/configurator/reactions/index.ts | 1 + .../configurator/reactions/unlimited.ts | 35 +++++ apps/web/process/hooks/init/get-users.js | 37 +++++ apps/web/process/hooks/init/index.js | 1 + apps/web/process/types.ts | 2 +- apps/web/server/middleware.ts | 18 ++- apps/web/server/routers/calculate/index.ts | 38 +++-- .../server/routers/calculate/lib/request.ts | 10 +- apps/web/server/routers/quote/index.ts | 38 +++-- packages/ui/elements/index.ts | 1 + packages/ui/elements/tag.js | 1 + 36 files changed, 386 insertions(+), 143 deletions(-) create mode 100644 apps/web/Components/Calculation/Form/Unlimited/config.ts create mode 100644 apps/web/Components/Calculation/Form/Unlimited/index.jsx create mode 100644 apps/web/Components/Layout/Page.jsx create mode 100644 apps/web/config/users.js create mode 100644 apps/web/pages/unlimited.jsx create mode 100644 apps/web/process/configurator/reactions/unlimited.ts create mode 100644 apps/web/process/hooks/init/get-users.js create mode 100644 packages/ui/elements/tag.js diff --git a/.env b/.env index eb78342..71125d0 100644 --- a/.env +++ b/.env @@ -2,9 +2,6 @@ USE_DEV_COLORS= BASE_PATH= -####### USERS ######## -USERS_SUPER=["akalinina","vchikalkin"] - ####### URLS ######## URL_GET_USER_DIRECT= URL_CRM_GRAPHQL_DIRECT= diff --git a/apps/web/Components/Calculation/Form/Unlimited/config.ts b/apps/web/Components/Calculation/Form/Unlimited/config.ts new file mode 100644 index 0000000..2c5cc34 --- /dev/null +++ b/apps/web/Components/Calculation/Form/Unlimited/config.ts @@ -0,0 +1,12 @@ +import type { FormTabRows } from '../../lib/render-rows'; + +export const id = 'unlimited'; +export const title = 'Без ограничений'; + +export const rows: FormTabRows = [ + [['cbxDisableChecks', 'selectUser']], + [['selectTarif', 'tbxCreditRate', 'selectRate']], + [['tbxMinPriceChange', 'tbxMaxPriceChange']], + [['tbxImporterRewardPerc', 'tbxImporterRewardRub']], + [['tbxBonusCoefficient', 'tbxComissionRub', 'tbxComissionPerc']], +]; diff --git a/apps/web/Components/Calculation/Form/Unlimited/index.jsx b/apps/web/Components/Calculation/Form/Unlimited/index.jsx new file mode 100644 index 0000000..91f340f --- /dev/null +++ b/apps/web/Components/Calculation/Form/Unlimited/index.jsx @@ -0,0 +1,12 @@ +import renderFormRows from '../../lib/render-rows'; +import { id, rows, title } from './config'; + +function Unlimited() { + return renderFormRows(rows); +} + +export default { + Component: Unlimited, + id, + title, +}; diff --git a/apps/web/Components/Calculation/Form/index.jsx b/apps/web/Components/Calculation/Form/index.jsx index 175cb11..7ba84b9 100644 --- a/apps/web/Components/Calculation/Form/index.jsx +++ b/apps/web/Components/Calculation/Form/index.jsx @@ -5,12 +5,22 @@ import Leasing from './Leasing'; import LeasingObject from './LeasingObject'; import Payments from './Payments'; import SupplierAgent from './SupplierAgent'; +import Unlimited from './Unlimited'; import Background from '@/Components/Layout/Background'; import { min } from '@/styles/mq'; import styled from 'styled-components'; import Tabs from 'ui/elements/layout/Tabs'; -const formTabs = [Leasing, Payments, LeasingObject, SupplierAgent, Insurance, AddProduct, CreateKP]; +const formTabs = [ + Leasing, + Payments, + LeasingObject, + SupplierAgent, + Insurance, + AddProduct, + CreateKP, + Unlimited, +]; const Wrapper = styled(Background)` padding: 4px 6px; @@ -32,17 +42,19 @@ const ComponentWrapper = styled.div` } `; -function Form() { +function Form({ prune }) { return ( - {formTabs.map(({ id, title, Component }) => ( - - - - - - ))} + {formTabs + .filter((tab) => !prune?.includes(tab.id)) + .map(({ id, title, Component }) => ( + + + + + + ))} ); diff --git a/apps/web/Components/Calculation/config/elements-components.ts b/apps/web/Components/Calculation/config/elements-components.ts index 56d946a..774b1de 100644 --- a/apps/web/Components/Calculation/config/elements-components.ts +++ b/apps/web/Components/Calculation/config/elements-components.ts @@ -131,6 +131,7 @@ const components = wrapComponentsMap({ tbxBonusCoefficient: e.InputNumber, selectLeasingWithoutKasko: e.Select, tbxVIN: e.Input, + selectUser: e.Select, /** Readonly Elements */ labelLeaseObjectRisk: e.Text, diff --git a/apps/web/Components/Calculation/config/elements-props.tsx b/apps/web/Components/Calculation/config/elements-props.tsx index 95c1a7c..ddc752b 100644 --- a/apps/web/Components/Calculation/config/elements-props.tsx +++ b/apps/web/Components/Calculation/config/elements-props.tsx @@ -444,6 +444,10 @@ const props: Partial = { direction: 'vertical', }, }, + selectUser: { + showSearch: true, + optionFilterProp: 'label', + }, }; export default props; diff --git a/apps/web/Components/Calculation/config/elements-titles.ts b/apps/web/Components/Calculation/config/elements-titles.ts index ba37e87..81b3f67 100644 --- a/apps/web/Components/Calculation/config/elements-titles.ts +++ b/apps/web/Components/Calculation/config/elements-titles.ts @@ -125,6 +125,7 @@ const titles: Record = { tbxBonusCoefficient: 'Коэффициент снижения бонуса', selectLeasingWithoutKasko: 'Лизинг без КАСКО', tbxVIN: 'VIN', + selectUser: 'Пользователь', /** Link Elements */ linkDownloadKp: '', diff --git a/apps/web/Components/Calculation/config/elements-types.ts b/apps/web/Components/Calculation/config/elements-types.ts index 8142aa5..de258b4 100644 --- a/apps/web/Components/Calculation/config/elements-types.ts +++ b/apps/web/Components/Calculation/config/elements-types.ts @@ -162,6 +162,7 @@ const types = wrapElementsTypes({ tbxBonusCoefficient: t.Value, selectLeasingWithoutKasko: t.Options, tbxVIN: t.Value, + selectUser: t.Options, labelLeaseObjectRisk: t.Readonly, tbxInsKaskoPriceLeasePeriod: t.Readonly, diff --git a/apps/web/Components/Calculation/config/map/values.ts b/apps/web/Components/Calculation/config/map/values.ts index 5271277..d3fe420 100644 --- a/apps/web/Components/Calculation/config/map/values.ts +++ b/apps/web/Components/Calculation/config/map/values.ts @@ -128,6 +128,7 @@ const elementsToValues = wrapElementsMap({ tbxMinPriceChange: 'minPriceChange', tbxBonusCoefficient: 'bonusCoefficient', tbxVIN: 'vin', + selectUser: 'user', /** Readonly Elements */ labelLeaseObjectRisk: 'leaseObjectRiskName', diff --git a/apps/web/Components/Layout/Logo.jsx b/apps/web/Components/Layout/Logo.jsx index 509569f..7edee39 100644 --- a/apps/web/Components/Layout/Logo.jsx +++ b/apps/web/Components/Layout/Logo.jsx @@ -1,10 +1,13 @@ /* eslint-disable react/forbid-component-props */ import styles from './Logo.module.css'; +import { useStore } from '@/stores/hooks'; +import getColors from '@/styles/colors'; import { min } from '@/styles/mq'; +import { observer } from 'mobx-react-lite'; import Image from 'next/image'; import logo from 'public/assets/images/logo-primary.svg'; import styled from 'styled-components'; -import { Flex } from 'ui'; +import { Flex, Tag } from 'ui'; const ImageWrapper = styled.div` width: 100px; @@ -26,13 +29,41 @@ const LogoText = styled.h3` } `; +const TagWrapper = styled.div` + font-family: 'Montserrat'; + font-weight: 500; + * { + font-size: 0.7rem; + } +`; + +const { COLOR_PRIMARY } = getColors(); + +const UnlimitedTag = observer(() => { + const { $process } = useStore(); + if ($process.has('Unlimited')) { + return ( + + + без ограничений + + + ); + } + + return false; +}); + function Logo() { return ( logo - Лизинговый Калькулятор + + Лизинговый Калькулятор + + ); } diff --git a/apps/web/Components/Layout/Page.jsx b/apps/web/Components/Layout/Page.jsx new file mode 100644 index 0000000..b2a6439 --- /dev/null +++ b/apps/web/Components/Layout/Page.jsx @@ -0,0 +1,27 @@ +import { min } from '@/styles/mq'; +import styled from 'styled-components'; +import { Box } from 'ui/grid'; + +export const Grid = styled(Box)` + display: flex; + flex-direction: column; + gap: 10px; + + ${min('laptop')} { + display: grid; + align-items: flex-start; + grid-template-columns: 2fr 1fr; + } + + ${min('laptop-hd')} { + grid-template-columns: 2fr 1fr 1.5fr; + } + + ${min('desktop')} { + margin: 8px 5%; + } + + ${min('desktop-xl')} { + margin: 8px 10%; + } +`; diff --git a/apps/web/api/core/types/calculate.ts b/apps/web/api/core/types/calculate.ts index 77887b5..72d500a 100644 --- a/apps/web/api/core/types/calculate.ts +++ b/apps/web/api/core/types/calculate.ts @@ -138,8 +138,13 @@ const AdditionalDataSchema = z.object({ export type AdditionalData = z.infer; +const flagsSchema = z.object({ + DISABLE_CHECKS_RESULTS: z.boolean(), +}); + export const RequestCalculateSchema = z.object({ additionalData: AdditionalDataSchema, + flags: flagsSchema.optional(), preparedPayments: PreparedPaymentSchema, preparedValues: PreparedValuesSchema, }); diff --git a/apps/web/api/user/tools.ts b/apps/web/api/user/tools.ts index 3539d54..815775c 100644 --- a/apps/web/api/user/tools.ts +++ b/apps/web/api/user/tools.ts @@ -1,13 +1,8 @@ import type { User } from './types'; -import { publicRuntimeConfigSchema } from '@/config/schema/runtime-config'; -import getConfig from 'next/config'; - -const { publicRuntimeConfig } = getConfig(); -const { USERS_SUPER } = publicRuntimeConfigSchema.parse(publicRuntimeConfig); +import { usersSuper } from '@/config/users'; export function love(user: User) { - const superUsers: string[] = JSON.parse(USERS_SUPER); - if (superUsers?.includes(user.username)) user.displayName += '🧡'; + if (usersSuper?.includes(user.username)) user.displayName += '🧡'; return user; } diff --git a/apps/web/config/default-options.ts b/apps/web/config/default-options.ts index 10c5b9b..ab4c2a5 100644 --- a/apps/web/config/default-options.ts +++ b/apps/web/config/default-options.ts @@ -493,6 +493,7 @@ const defaultOptions: CalculationOptions = { tbxBonusCoefficient: [], selectLeasingWithoutKasko: [], tbxVIN: [], + selectUser: [], }; export default defaultOptions; diff --git a/apps/web/config/default-statuses.ts b/apps/web/config/default-statuses.ts index ec3c327..dbdcb41 100644 --- a/apps/web/config/default-statuses.ts +++ b/apps/web/config/default-statuses.ts @@ -86,6 +86,7 @@ const defaultStatuses: CalculationStatuses = { selectTelematic: 'Default', selectTownRegistration: 'Default', selectTracker: 'Default', + selectUser: 'Default', tbxAddEquipmentPrice: 'Default', tbxBonusCoefficient: 'Default', tbxCalcBrokerRewardSum: 'Disabled', diff --git a/apps/web/config/default-values.ts b/apps/web/config/default-values.ts index 5050599..1f7bb79 100644 --- a/apps/web/config/default-values.ts +++ b/apps/web/config/default-values.ts @@ -137,6 +137,7 @@ const defaultValues: CalculationValues = { vehicleTaxInYear: 0, withTrailer: false, vin: null, + user: null, }; export default defaultValues; diff --git a/apps/web/config/schema/env.js b/apps/web/config/schema/env.js index 358a120..3508c8e 100644 --- a/apps/web/config/schema/env.js +++ b/apps/web/config/schema/env.js @@ -10,7 +10,6 @@ const envSchema = z.object({ URL_CRM_GRAPHQL_DIRECT: z.string(), URL_GET_USER_DIRECT: z.string(), USE_DEV_COLORS: z.unknown().optional().transform(Boolean), - USERS_SUPER: z.string().optional().default(''), }); module.exports = envSchema; diff --git a/apps/web/config/schema/runtime-config.js b/apps/web/config/schema/runtime-config.js index 40bf145..1f59d27 100644 --- a/apps/web/config/schema/runtime-config.js +++ b/apps/web/config/schema/runtime-config.js @@ -3,7 +3,6 @@ const envSchema = require('./env'); const publicRuntimeConfigSchema = envSchema.pick({ BASE_PATH: true, USE_DEV_COLORS: true, - USERS_SUPER: true, }); const serverRuntimeConfigSchema = envSchema.pick({ diff --git a/apps/web/config/schema/values.ts b/apps/web/config/schema/values.ts index d924ccd..e1bd311 100644 --- a/apps/web/config/schema/values.ts +++ b/apps/web/config/schema/values.ts @@ -123,6 +123,7 @@ const ValuesSchema = z.object({ vehicleTaxInYear: z.number(), withTrailer: z.boolean(), vin: z.string().nullable(), + user: z.string().nullable(), /** * Link Values diff --git a/apps/web/config/users.js b/apps/web/config/users.js new file mode 100644 index 0000000..59b581b --- /dev/null +++ b/apps/web/config/users.js @@ -0,0 +1,3 @@ +export const unlimitedRoles = ['Калькулятор без ограничений']; +export const defaultRoles = ['МПЛ']; +export const usersSuper = ['akalinina', 'vchikalkin']; diff --git a/apps/web/graphql/crm.query.graphql b/apps/web/graphql/crm.query.graphql index e89768c..6847f24 100644 --- a/apps/web/graphql/crm.query.graphql +++ b/apps/web/graphql/crm.query.graphql @@ -639,3 +639,12 @@ query GetInsuranceCompanies { label: name } } + +query GetRoles($roleName: String) { + roles(name: $roleName) { + systemusers { + label: fullname + value: domainname + } + } +} diff --git a/apps/web/graphql/crm.types.ts b/apps/web/graphql/crm.types.ts index 361d813..4ea012a 100644 --- a/apps/web/graphql/crm.types.ts +++ b/apps/web/graphql/crm.types.ts @@ -470,6 +470,13 @@ export type GetInsuranceCompaniesQueryVariables = Exact<{ [key: string]: never; export type GetInsuranceCompaniesQuery = { __typename?: 'Query', accounts: Array<{ __typename?: 'account', evo_type_ins_policy: Array | null, evo_evokasko_access: boolean | null, evo_inn: string | null, value: string | null, label: string | null } | null> | null }; +export type GetRolesQueryVariables = Exact<{ + roleName: InputMaybe; +}>; + + +export type GetRolesQuery = { __typename?: 'Query', roles: Array<{ __typename?: 'role', systemusers: Array<{ __typename?: 'systemuser', label: string | null, value: string | null } | null> | null } | null> | null }; + export type GetQuoteAddProductDataQueryVariables = Exact<{ quoteId: Scalars['Uuid']; }>; @@ -642,6 +649,7 @@ export const GetInsNsibTypesDocument = {"kind":"Document","definitions":[{"kind" export const GetLeasingWithoutKaskoTypesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetLeasingWithoutKaskoTypes"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"currentDate"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"DateTime"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"evo_addproduct_types"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"statecode"},"value":{"kind":"IntValue","value":"0"}},{"kind":"Argument","name":{"kind":"Name","value":"evo_product_type"},"value":{"kind":"IntValue","value":"100000007"}},{"kind":"Argument","name":{"kind":"Name","value":"evo_datefrom_param"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"lte"},"value":{"kind":"Variable","name":{"kind":"Name","value":"currentDate"}}}]}},{"kind":"Argument","name":{"kind":"Name","value":"evo_dateto_param"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"gte"},"value":{"kind":"Variable","name":{"kind":"Name","value":"currentDate"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CoreAddProductTypesFields"}},{"kind":"Field","name":{"kind":"Name","value":"evo_product_type"}},{"kind":"Field","name":{"kind":"Name","value":"evo_min_period"}},{"kind":"Field","name":{"kind":"Name","value":"evo_max_period"}},{"kind":"Field","name":{"kind":"Name","value":"evo_min_price"}},{"kind":"Field","name":{"kind":"Name","value":"evo_max_price"}},{"kind":"Field","name":{"kind":"Name","value":"evo_leasingobject_types"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"evo_leasingobject_typeid"}}]}},{"kind":"Field","name":{"kind":"Name","value":"evo_visible_calc"}},{"kind":"Field","name":{"kind":"Name","value":"evo_min_first_payment_perc"}},{"kind":"Field","name":{"kind":"Name","value":"evo_max_first_payment_perc"}},{"kind":"Field","name":{"kind":"Name","value":"evo_models"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"evo_modelid"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CoreAddProductTypesFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"evo_addproduct_type"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"evo_graph_price"}},{"kind":"Field","alias":{"kind":"Name","value":"label"},"name":{"kind":"Name","value":"evo_name"}},{"kind":"Field","alias":{"kind":"Name","value":"value"},"name":{"kind":"Name","value":"evo_addproduct_typeid"}}]}}]} as unknown as DocumentNode; export const GetInsuranceCompanyDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetInsuranceCompany"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"accountId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Uuid"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"account"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"accountid"},"value":{"kind":"Variable","name":{"kind":"Name","value":"accountId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"evo_osago_with_kasko"}}]}}]}}]} as unknown as DocumentNode; export const GetInsuranceCompaniesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetInsuranceCompanies"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"accounts"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"evo_account_type"},"value":{"kind":"ListValue","values":[{"kind":"IntValue","value":"100000002"}]}},{"kind":"Argument","name":{"kind":"Name","value":"statecode"},"value":{"kind":"IntValue","value":"0"}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"evo_type_ins_policy"}},{"kind":"Field","name":{"kind":"Name","value":"evo_evokasko_access"}},{"kind":"Field","name":{"kind":"Name","value":"evo_inn"}},{"kind":"Field","alias":{"kind":"Name","value":"value"},"name":{"kind":"Name","value":"accountid"}},{"kind":"Field","alias":{"kind":"Name","value":"label"},"name":{"kind":"Name","value":"name"}}]}}]}}]} as unknown as DocumentNode; +export const GetRolesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetRoles"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"roleName"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"roles"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"roleName"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"systemusers"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","alias":{"kind":"Name","value":"label"},"name":{"kind":"Name","value":"fullname"}},{"kind":"Field","alias":{"kind":"Name","value":"value"},"name":{"kind":"Name","value":"domainname"}}]}}]}}]}}]} as unknown as DocumentNode; export const GetQuoteAddProductDataDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetQuoteAddProductData"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"quoteId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Uuid"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"quote"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"quoteId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"quoteId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"evo_addproduct_types"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"evo_product_type"}},{"kind":"Field","name":{"kind":"Name","value":"evo_addproduct_typeid"}}]}}]}}]}}]} as unknown as DocumentNode; export const GetQuoteBonusDataDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetQuoteBonusData"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"quoteId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Uuid"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"quote"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"quoteId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"quoteId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"evo_sale_bonus"}}]}}]}}]} as unknown as DocumentNode; export const GetQuoteConfiguratorDataDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetQuoteConfiguratorData"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"quoteId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Uuid"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"quote"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"quoteId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"quoteId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"evo_baseproductid"}},{"kind":"Field","name":{"kind":"Name","value":"evo_client_typeid"}},{"kind":"Field","name":{"kind":"Name","value":"evo_msfo_irr"}}]}}]}}]} as unknown as DocumentNode; diff --git a/apps/web/pages/_document.jsx b/apps/web/pages/_document.jsx index 48f85de..9a4eda7 100644 --- a/apps/web/pages/_document.jsx +++ b/apps/web/pages/_document.jsx @@ -36,7 +36,7 @@ export default class MyDocument extends Document { - + {metaFavicon} diff --git a/apps/web/pages/index.jsx b/apps/web/pages/index.jsx index 158869c..b6d9a47 100644 --- a/apps/web/pages/index.jsx +++ b/apps/web/pages/index.jsx @@ -2,41 +2,16 @@ import { getUser } from '@/api/user/query'; import initializeApollo from '@/apollo/client'; import * as Calculation from '@/Components/Calculation'; import { Error } from '@/Components/Common/Error'; +import { Grid } from '@/Components/Layout/Page'; import Output from '@/Components/Output'; +import { defaultRoles } from '@/config/users'; import * as CRMTypes from '@/graphql/crm.types'; import { useInsuranceData, useMainData, useReactions } from '@/process/hooks'; import { getInitialData } from '@/process/hooks/init'; -import { min } from '@/styles/mq'; import { dehydrate, QueryClient } from '@tanstack/react-query'; import Head from 'next/head'; -import styled from 'styled-components'; -import { Box } from 'ui/grid'; -const Grid = styled(Box)` - display: flex; - flex-direction: column; - gap: 10px; - - ${min('laptop')} { - display: grid; - align-items: flex-start; - grid-template-columns: 2fr 1fr; - } - - ${min('laptop-hd')} { - grid-template-columns: 2fr 1fr 1.5fr; - } - - ${min('desktop')} { - margin: 8px 5%; - } - - ${min('desktop-xl')} { - margin: 8px 10%; - } -`; - -function Home(props) { +export default function Home(props) { useMainData(); useInsuranceData(); useReactions(); @@ -48,65 +23,69 @@ function Home(props) { Лизинговый калькулятор - Эволюция - + ); } -/** @type {import('next').GetServerSideProps} */ -export const getServerSideProps = async ({ req }) => { - const { cookie = '' } = req.headers; +export const makeGetServerSideProps = ({ roles }) => + /** @type {import('next').GetServerSideProps} */ + ( + async function ({ req }) { + const { cookie = '' } = req.headers; - const queryClient = new QueryClient(); + const queryClient = new QueryClient(); - const user = await queryClient.fetchQuery(['user'], ({ signal }) => - getUser({ - headers: { - cookie, - }, - signal, - }) + const user = await queryClient.fetchQuery(['user'], ({ signal }) => + getUser({ + headers: { + cookie, + }, + signal, + }) + ); + + const apolloClient = initializeApollo(); + + try { + const { + data: { systemuser }, + } = await apolloClient.query({ + fetchPolicy: 'network-only', + query: CRMTypes.GetSystemUserDocument, + variables: { + domainname: user.domainName, + }, + }); + + if (!systemuser?.roles?.some((x) => x?.name && roles.includes(x.name))) { + return { + props: { statusCode: 403 }, + }; + } + const { values, options } = await getInitialData(apolloClient, user); + + return { + props: { + calculation: { + options, + values, + }, + initialApolloState: apolloClient.cache.extract(), + initialQueryState: dehydrate(queryClient), + statusCode: 200, + }, + }; + } catch (error) { + return { + props: { + error: JSON.stringify(error), + statusCode: 500, + }, + }; + } + } ); - const apolloClient = initializeApollo(); - - try { - const { - data: { systemuser }, - } = await apolloClient.query({ - query: CRMTypes.GetSystemUserDocument, - variables: { - domainname: user.domainName, - }, - }); - - if (!systemuser.roles.some((x) => x.name === 'МПЛ')) { - return { - props: { statusCode: 403 }, - }; - } - const { values, options } = await getInitialData(apolloClient, user); - - return { - props: { - calculation: { - options, - values, - }, - initialApolloState: apolloClient.cache.extract(), - initialQueryState: dehydrate(queryClient), - statusCode: 200, - }, - }; - } catch (error) { - return { - props: { - error: JSON.stringify(error), - statusCode: 500, - }, - }; - } -}; - -export default Home; +export const getServerSideProps = makeGetServerSideProps({ roles: defaultRoles }); diff --git a/apps/web/pages/unlimited.jsx b/apps/web/pages/unlimited.jsx new file mode 100644 index 0000000..d5d8c4f --- /dev/null +++ b/apps/web/pages/unlimited.jsx @@ -0,0 +1,37 @@ +import { makeGetServerSideProps } from '.'; +import * as Calculation from '@/Components/Calculation'; +import { Error } from '@/Components/Common/Error'; +import { Grid } from '@/Components/Layout/Page'; +import Output from '@/Components/Output'; +import { unlimitedRoles } from '@/config/users'; +import { useGetUsers, useInsuranceData, useMainData, useReactions } from '@/process/hooks'; +import { useStore } from '@/stores/hooks'; +import Head from 'next/head'; + +export default function Unlimited(props) { + const store = useStore(); + store.$process.add('Unlimited'); + + useMainData(); + useGetUsers(); + useInsuranceData(); + useReactions(); + + if (props.statusCode !== 200) return ; + + return ( + + + Лизинговый калькулятор без ограничений - Эволюция + + + + + + + ); +} + +export const getServerSideProps = makeGetServerSideProps({ + roles: unlimitedRoles, +}); diff --git a/apps/web/process/configurator/reactions/index.ts b/apps/web/process/configurator/reactions/index.ts index e294884..1b87c74 100644 --- a/apps/web/process/configurator/reactions/index.ts +++ b/apps/web/process/configurator/reactions/index.ts @@ -1,3 +1,4 @@ export { default as filters } from './filters'; +export { default as unlimited } from './unlimited'; export { default as validation } from './validation'; export { default as values } from './values'; diff --git a/apps/web/process/configurator/reactions/unlimited.ts b/apps/web/process/configurator/reactions/unlimited.ts new file mode 100644 index 0000000..7dfd80c --- /dev/null +++ b/apps/web/process/configurator/reactions/unlimited.ts @@ -0,0 +1,35 @@ +import * as CRMTypes from '@/graphql/crm.types'; +import type { ProcessContext } from '@/process/types'; +import { reaction } from 'mobx'; +import { makeDisposable, normalizeOptions } from 'tools'; + +export default function unlimitedReactions({ store, apolloClient }: ProcessContext) { + const { $calculation, $process } = store; + + makeDisposable( + () => + reaction( + () => $calculation.element('selectUser').getValue(), + async (domainname) => { + const { + data: { leads }, + } = await apolloClient.query({ + query: CRMTypes.GetLeadsDocument, + variables: { domainname }, + }); + + $calculation.element('selectLead').setOptions(normalizeOptions(leads)); + + const { + data: { opportunities }, + } = await apolloClient.query({ + query: CRMTypes.GetOpportunitiesDocument, + variables: { domainname }, + }); + + $calculation.element('selectOpportunity').setOptions(normalizeOptions(opportunities)); + } + ), + () => !$process.has('Unlimited') + ); +} diff --git a/apps/web/process/hooks/init/get-users.js b/apps/web/process/hooks/init/get-users.js new file mode 100644 index 0000000..bd70a21 --- /dev/null +++ b/apps/web/process/hooks/init/get-users.js @@ -0,0 +1,37 @@ +import * as CRMTypes from '@/graphql/crm.types'; +import { useStore } from '@/stores/hooks'; +import { useApolloClient } from '@apollo/client'; +import { useEffect } from 'react'; +import { normalizeOptions } from 'tools'; + +/** + * @param {import('@apollo/client').ApolloClient} apolloClient + * @param {*} onCompleted + */ +export function getUsers({ query }, onCompleted) { + query({ + query: CRMTypes.GetRolesDocument, + variables: { roleName: 'МПЛ' }, + }).then(({ data }) => { + const users = data.roles?.flatMap((x) => x?.systemusers); + onCompleted({ + selectUser: users, + }); + }); +} + +export function useGetUsers() { + const { $calculation } = useStore(); + const apolloClient = useApolloClient(); + + function handleOnCompleted(options) { + Object.keys(options).forEach((elementName) => { + const elementOptions = options[elementName]; + $calculation.element(elementName).setOptions(normalizeOptions(elementOptions)); + }); + } + + useEffect(() => { + getUsers(apolloClient, handleOnCompleted); + }, []); +} diff --git a/apps/web/process/hooks/init/index.js b/apps/web/process/hooks/init/index.js index eee9f13..2cf7203 100644 --- a/apps/web/process/hooks/init/index.js +++ b/apps/web/process/hooks/init/index.js @@ -1,3 +1,4 @@ export * from './get-initial-data'; export * from './get-insurance-data'; export * from './get-main-data'; +export * from './get-users'; diff --git a/apps/web/process/types.ts b/apps/web/process/types.ts index b13166d..98cc755 100644 --- a/apps/web/process/types.ts +++ b/apps/web/process/types.ts @@ -9,7 +9,7 @@ export type ProcessContext = { queryClient: QueryClient; store: RootStore; trpcClient: TRPCPureClient; - user: User | undefined; + user: Pick | undefined; }; export type Process = { diff --git a/apps/web/server/middleware.ts b/apps/web/server/middleware.ts index 553e146..fedce85 100644 --- a/apps/web/server/middleware.ts +++ b/apps/web/server/middleware.ts @@ -1,19 +1,33 @@ import { t } from './trpc'; +import initializeApollo from '@/apollo/client'; +import { unlimitedRoles } from '@/config/users'; +import * as CRMTypes from '@/graphql/crm.types'; import { TRPCError } from '@trpc/server'; /** * @see https://trpc.io/docs/v10/middlewares */ -export const userMiddleware = t.middleware(({ ctx, next }) => { +export const userMiddleware = t.middleware(async ({ ctx, next }) => { if (process.env.NODE_ENV !== 'development' && !ctx.user) { throw new TRPCError({ code: 'UNAUTHORIZED', }); } + const apolloClient = initializeApollo(); + + const { + data: { systemuser }, + } = await apolloClient.query({ + query: CRMTypes.GetSystemUserDocument, + variables: { + domainname: ctx.user.domainName, + }, + }); + return next({ ctx: { - isAdmin: false, + unlimited: systemuser?.roles?.some((x) => x?.name && unlimitedRoles.includes(x.name)), }, }); }); diff --git a/apps/web/server/routers/calculate/index.ts b/apps/web/server/routers/calculate/index.ts index f4c7a6c..50aceb9 100644 --- a/apps/web/server/routers/calculate/index.ts +++ b/apps/web/server/routers/calculate/index.ts @@ -4,6 +4,7 @@ import { transformCalculateResults } from './lib/transform'; import { validate } from './lib/validation'; import { CalculateInputSchema, CalculateOutputSchema } from './types'; import { calculate } from '@/api/core/query'; +import type { User } from '@/api/user/types'; import initializeApollo from '@/apollo/client'; import { protectedProcedure } from '@/server/procedure'; import { QueryClient } from '@tanstack/react-query'; @@ -16,30 +17,37 @@ export const calculateRouter = router({ const apolloClient = initializeApollo(); const queryClient = new QueryClient(); - const validationResult = await validate({ - context: { - apolloClient, - queryClient, - user: ctx.user, - }, - input, - }); + if (ctx.unlimited === false) { + const validationResult = await validate({ + context: { + apolloClient, + queryClient, + user: ctx.user, + }, + input, + }); - if (validationResult.success === false) { - return { - error: validationResult.error, - success: false, - }; + if (validationResult.success === false) { + return { + error: validationResult.error, + success: false, + }; + } + } + + let user: Pick = { domainName: ctx.user.domainName }; + if (ctx.unlimited && input.values.user) { + user = { domainName: input.values.user }; } const requestData = await createRequestData({ context: { apolloClient, queryClient, - user: ctx.user, + ...ctx, + user, }, input, - user: ctx.user, }); const calculateResult = await calculate(requestData); diff --git a/apps/web/server/routers/calculate/lib/request.ts b/apps/web/server/routers/calculate/lib/request.ts index e1b3b1f..1a9fb37 100644 --- a/apps/web/server/routers/calculate/lib/request.ts +++ b/apps/web/server/routers/calculate/lib/request.ts @@ -1,7 +1,6 @@ /* eslint-disable sonarjs/cognitive-complexity */ import type { CalculateInput, Context } from '../types'; import type * as CoreTypes from '@/api/core/types'; -import type { User } from '@/api/user/types'; import { ESN, NSIB_MAX, VAT } from '@/constants/values'; import * as CRMTypes from '@/graphql/crm.types'; import helper from '@/process/calculate/lib/helper'; @@ -13,9 +12,8 @@ import { max, sum } from 'radash'; dayjs.extend(utc); type Input = { - context: Context; + context: Context & { unlimited?: boolean }; input: CalculateInput; - user: User; }; type PreparedValuesGetters = { @@ -29,9 +27,8 @@ type AdditionalDataGetters = { export async function createRequestData({ context, input, - user, }: Input): Promise { - const { apolloClient } = context; + const { apolloClient, user, unlimited } = context; const { values, insurance, payments } = input; const { RUB } = createCurrencyUtility({ apolloClient }); @@ -1232,6 +1229,9 @@ export async function createRequestData({ return { additionalData, + flags: { + DISABLE_CHECKS_RESULTS: unlimited, + }, preparedPayments, preparedValues, }; diff --git a/apps/web/server/routers/quote/index.ts b/apps/web/server/routers/quote/index.ts index 100c765..4f8b854 100644 --- a/apps/web/server/routers/quote/index.ts +++ b/apps/web/server/routers/quote/index.ts @@ -13,6 +13,7 @@ import { } from './types'; import { calculate } from '@/api/core/query'; import { createKP } from '@/api/crm/query'; +import type { User } from '@/api/user/types'; import initializeApollo from '@/apollo/client'; import defaultValues from '@/config/default-values'; import * as insuranceTable from '@/config/tables/insurance-table'; @@ -88,30 +89,37 @@ export const quoteRouter = router({ const apolloClient = initializeApollo(); const queryClient = new QueryClient(); - const validationResult = await validate({ - context: { - apolloClient, - queryClient, - user: ctx.user, - }, - input, - }); + if (ctx.unlimited === false) { + const validationResult = await validate({ + context: { + apolloClient, + queryClient, + user: ctx.user, + }, + input, + }); - if (validationResult.success === false) { - return { - error: validationResult.error, - success: false, - }; + if (validationResult.success === false) { + return { + error: validationResult.error, + success: false, + }; + } + } + + let user: Pick = { domainName: ctx.user.domainName }; + if (ctx.unlimited && input.values.user) { + user = { domainName: input.values.user }; } const requestData = await createRequestData({ context: { apolloClient, queryClient, - user: ctx.user, + ...ctx, + user, }, input, - user: ctx.user, }); const calculateResult = await calculate(requestData); diff --git a/packages/ui/elements/index.ts b/packages/ui/elements/index.ts index ae1c1d3..7b14df4 100644 --- a/packages/ui/elements/index.ts +++ b/packages/ui/elements/index.ts @@ -13,5 +13,6 @@ export { default as Segmented } from './Segmented'; export { default as Select } from './Select'; export { default as Switch } from './Switch'; export { default as Table } from './Table'; +export * from './tag'; export { default as Text } from './Text'; export { default as Tooltip } from './Tooltip'; diff --git a/packages/ui/elements/tag.js b/packages/ui/elements/tag.js new file mode 100644 index 0000000..2bfffd1 --- /dev/null +++ b/packages/ui/elements/tag.js @@ -0,0 +1 @@ +export { Tag } from 'antd';