From 0d8ea707342ce4bf361a817c018a0fa8142fe668 Mon Sep 17 00:00:00 2001 From: vchikalkin Date: Thu, 16 Nov 2023 17:09:22 +0300 Subject: [PATCH] apps/web: add base elements validation --- apps/web/api/ius/query.ts | 7 ++++--- apps/web/app/ius/[slug]/page.tsx | 4 ++-- apps/web/components/Form/Buttons.tsx | 24 ++++++++++++++++++++---- apps/web/components/Form/Elements.tsx | 10 ++++++++-- apps/web/config/env.js | 16 ++-------------- apps/web/config/urls.ts | 21 ++++++++++++++------- apps/web/constants/colors.ts | 4 ++-- apps/web/next.config.js | 4 ++-- apps/web/store/ius/form.ts | 20 ++++++++++++++++++++ apps/web/utils/common.ts | 2 +- apps/web/utils/url.ts | 2 +- 11 files changed, 76 insertions(+), 38 deletions(-) diff --git a/apps/web/api/ius/query.ts b/apps/web/api/ius/query.ts index be73cad..8f54471 100644 --- a/apps/web/api/ius/query.ts +++ b/apps/web/api/ius/query.ts @@ -1,9 +1,10 @@ import type * as t from './types'; -import { urls } from '@/config/urls'; +import { getUrls } from '@/config/urls'; import type { CreateUrl } from '@/utils/url'; import type { WretchError } from 'wretch'; import wretch from 'wretch'; +const urls = getUrls(); const api = wretch(urls.URL_UIS).errorType('json'); type Input = { createUrl: CreateUrl; payload?: unknown }; @@ -44,11 +45,11 @@ export async function getConditions({ createUrl }: Input) { .then((res) => res); } -export async function validate({ createUrl }: Input) { +export async function validate({ createUrl, payload }: Input) { const url = createUrl('/validate'); return api - .post(url) + .post(payload, url) .res((res) => res.ok) .then((res) => res) .catch((error: WretchError) => error.json as t.HttpValidationError); diff --git a/apps/web/app/ius/[slug]/page.tsx b/apps/web/app/ius/[slug]/page.tsx index fe60ec9..3e433b6 100644 --- a/apps/web/app/ius/[slug]/page.tsx +++ b/apps/web/app/ius/[slug]/page.tsx @@ -33,14 +33,14 @@ export default async function Page(pageProps: PageProps) { apiIUS.getMetaData({ createUrl }), apiIUS.getConfig({ createUrl }), ]).then(([data, metaData, { title }]) => { - const props = { data, metaData }; + const props = { data, metaData, pageUrlParams }; return ( - + ); }); diff --git a/apps/web/components/Form/Buttons.tsx b/apps/web/components/Form/Buttons.tsx index f454915..c3ddfcf 100644 --- a/apps/web/components/Form/Buttons.tsx +++ b/apps/web/components/Form/Buttons.tsx @@ -1,10 +1,12 @@ 'use client'; - +import * as apiIus from '@/api/ius/query'; import { useFormStore } from '@/store/ius/form'; +import { makeCreateUrl, type PageUrlParams } from '@/utils/url'; import { Button } from 'ui'; -export function Buttons() { - const { reset } = useFormStore(); +export function Buttons({ pageUrlParams }: { readonly pageUrlParams: PageUrlParams }) { + const { reset, setValidation, values } = useFormStore(); + const createUrl = makeCreateUrl(pageUrlParams); return (
@@ -17,7 +19,21 @@ export function Buttons() { Отмена - +
); } diff --git a/apps/web/components/Form/Elements.tsx b/apps/web/components/Form/Elements.tsx index 55c29ae..f2777cb 100644 --- a/apps/web/components/Form/Elements.tsx +++ b/apps/web/components/Form/Elements.tsx @@ -7,7 +7,7 @@ import { useEffect } from 'react'; import { ElementContainer } from 'ui'; export function Elements({ data, metaData }: Props) { - const { init, setValue, values } = useFormStore(); + const { init, setValue, validation, values } = useFormStore(); useEffect(() => { init(data); @@ -23,7 +23,13 @@ export function Elements({ data, metaData }: Props) { const Element = mapFieldTypeElement[fieldType]; return ( - + envSchema.parse(process.env); -const serverEnv = envSchema - .pick({ - URL_IUS_DIRECT: true, - }) - .parse(process.env); - -const clientEnv = envSchema - .pick({ - USE_DEV_COLORS: true, - }) - .parse(process.env); - -module.exports = { clientEnv, env, serverEnv }; +module.exports = { getEnv }; diff --git a/apps/web/config/urls.ts b/apps/web/config/urls.ts index 4fe9480..3df7e89 100644 --- a/apps/web/config/urls.ts +++ b/apps/web/config/urls.ts @@ -1,11 +1,18 @@ -import { serverEnv } from './env'; +import { getEnv } from './env'; import proxyUrls from '@/constants/urls'; import { isServer } from '@/utils/common'; -export const urls = isServer - ? { - URL_UIS: serverEnv.URL_IUS_DIRECT, - } - : { - URL_UIS: proxyUrls.URL_IUS_PROXY, +export function getUrls() { + if (isServer()) { + const env = getEnv(); + const { URL_IUS_DIRECT } = env; + + return { + URL_UIS: URL_IUS_DIRECT, }; + } + + return { + URL_UIS: proxyUrls.URL_IUS_PROXY, + }; +} diff --git a/apps/web/constants/colors.ts b/apps/web/constants/colors.ts index bd8188a..7319c91 100644 --- a/apps/web/constants/colors.ts +++ b/apps/web/constants/colors.ts @@ -1,4 +1,4 @@ -import { env } from '../config/env'; +import { getEnv } from '../config/env'; export const COLORS_PROD = { COLOR_DANGER: '#B20004', @@ -12,5 +12,5 @@ export const COLORS_DEV = { COLOR_SECONDARY: '#FD4047', COLOR_TERTIARTY: '#FF9112', }; - +const env = getEnv(); export const COLORS = env.USE_DEV_COLORS ? COLORS_DEV : COLORS_PROD; diff --git a/apps/web/next.config.js b/apps/web/next.config.js index 576def3..25dd65c 100644 --- a/apps/web/next.config.js +++ b/apps/web/next.config.js @@ -20,8 +20,8 @@ const nextConfig = { async rewrites() { return [ { - destination: env.URL_IUS_DIRECT + '/:path', - source: urls.URL_IUS_PROXY + '/:path', + destination: env.URL_IUS_DIRECT + '/:path*', + source: urls.URL_IUS_PROXY + '/:path*', }, ...favicons.map((fileName) => buildFaviconRewrite(`/${fileName}`)), ]; diff --git a/apps/web/store/ius/form.ts b/apps/web/store/ius/form.ts index 1644588..f7fba47 100644 --- a/apps/web/store/ius/form.ts +++ b/apps/web/store/ius/form.ts @@ -3,11 +3,18 @@ import { create } from 'zustand'; type Values = ResponseGetData; +type ElementValidation = { + message: string; + valid: boolean; +}; + type FormState = { defaultValues: Values; init: (values: Values) => void; reset: () => void; + setValidation: (input: { name: string } & ElementValidation) => void; setValue: ({ name, value }: { name: string; value: Values[number] }) => void; + validation: Record; values: Values; }; @@ -23,12 +30,25 @@ export const useFormStore = create((set) => ({ values: state.defaultValues, })); }, + setValidation: ({ message, name, valid }) => { + set((state) => ({ + validation: { + ...state.validation, + [name]: { message, valid }, + }, + })); + }, setValue: ({ name, value }) => set((state) => ({ + validation: { + ...state.validation, + [name]: undefined, + }, values: { ...state.values, [name]: value, }, })), + validation: {}, values: {}, })); diff --git a/apps/web/utils/common.ts b/apps/web/utils/common.ts index df6bd56..df38247 100644 --- a/apps/web/utils/common.ts +++ b/apps/web/utils/common.ts @@ -1 +1 @@ -export const isServer = typeof window === 'undefined'; +export const isServer = () => typeof window === 'undefined'; diff --git a/apps/web/utils/url.ts b/apps/web/utils/url.ts index 957102b..0fbd18d 100644 --- a/apps/web/utils/url.ts +++ b/apps/web/utils/url.ts @@ -8,7 +8,7 @@ export type PageUrlParams = ReturnType; export function makeCreateUrl({ path, urlSearchParams }: ReturnType) { return function (route: string) { - if (urlSearchParams) return `${path}${route}?${urlSearchParams}`; + if (urlSearchParams) return `${path}${route}?${new URLSearchParams(urlSearchParams)}`; return path + route; };