diff --git a/apps/web/api/ius/query.ts b/apps/web/api/ius/query.ts index 699d46d..9b14b22 100644 --- a/apps/web/api/ius/query.ts +++ b/apps/web/api/ius/query.ts @@ -67,3 +67,29 @@ export async function retract({ pageUrlParams, payload }: Input) { .then((res) => res) .catch((error: WretchError) => error.json as t.HttpValidationError); } + +export async function getDocumentTypes({ pageUrlParams }: Input) { + const url = createUrl({ ...pageUrlParams, route: '/documenttypes' }); + + return api + .get(url) + .res((res) => res.json()) + .then((res) => res); +} + +export async function uploadDocument({ + pageUrlParams, + document, + formData, +}: Input & { document: Pick; formData: FormData }) { + const url = createUrl({ + ...pageUrlParams, + route: '/document', + urlSearchParams: { ...pageUrlParams.urlSearchParams, ...document }, + }); + + return fetch(urls.URL_IUS + url, { + body: formData, + method: 'POST', + }); +} diff --git a/apps/web/api/ius/types.ts b/apps/web/api/ius/types.ts index 2fc2d35..8027dfc 100644 --- a/apps/web/api/ius/types.ts +++ b/apps/web/api/ius/types.ts @@ -11,10 +11,16 @@ export type MetaObject = { type Value = any; +export type Document = { + documentTypeId: string; + name: string; +}; + export type ResponseGetData = Record; export type ResponseMetaData = Record; export type ResponseConfig = { title: string }; export type ResponseConditions = string; +export type ResponseDocumentTypes = Document[]; export type HttpError = { errors: string[]; diff --git a/apps/web/app/ius/[slug]/page.tsx b/apps/web/app/ius/[slug]/page.tsx index 75460db..50f686a 100644 --- a/apps/web/app/ius/[slug]/page.tsx +++ b/apps/web/app/ius/[slug]/page.tsx @@ -29,8 +29,9 @@ export default async function Page(pageProps: PageProps) { apiIUS.getData({ pageUrlParams }), apiIUS.getMetaData({ pageUrlParams }), apiIUS.getConfig({ pageUrlParams }), - ]).then(([data, metaData, { title }]) => { - const props = { data, metaData, pageUrlParams, title }; + apiIUS.getDocumentTypes({ pageUrlParams }), + ]).then(([data, metaData, { title }, documentTypes]) => { + const props = { data, documentTypes, metaData, pageUrlParams, title }; return
; }); diff --git a/apps/web/components/Form/Buttons.tsx b/apps/web/components/Form/Buttons.tsx index 9ab6292..0fad1cd 100644 --- a/apps/web/components/Form/Buttons.tsx +++ b/apps/web/components/Form/Buttons.tsx @@ -1,16 +1,85 @@ +/* eslint-disable react/jsx-curly-newline */ /* eslint-disable no-negated-condition */ import { FormContext } from './context/form-context'; import * as apiIus from '@/api/ius/query'; import { useFormStore } from '@/store/ius/form'; import { useRouter } from 'next/navigation'; +import { pick } from 'radash'; +import { useCallback } from 'react'; import { useContext } from 'react'; import { Button } from 'ui'; +const ERROR_UPLOAD_DOCUMENT = 'Произошла ошибка при загрузке документов'; + export function Buttons() { const { reset, resetValidation, setValidation, values } = useFormStore(); - const { pageUrlParams, setFormStatus } = useContext(FormContext); + const { formFiles, pageUrlParams, setFormState } = useContext(FormContext); + const router = useRouter(); + const handleSave = useCallback(() => { + apiIus.save({ pageUrlParams, payload: values }).then((res) => { + if (typeof res !== 'boolean') { + setTimeout(() => { + setFormState({ status: 'edit' }); + }, 300); + Object.keys(res.errors).forEach((name) => { + const elementValidation = res?.errors?.[name]; + if (elementValidation) + setValidation({ message: elementValidation[0] ?? '', name, valid: false }); + }); + } else { + setFormState({ status: 'success' }); + setTimeout(() => { + router.refresh(); + }, 500); + } + }); + }, [pageUrlParams, router, setFormState, setValidation, values]); + + const handleUploadFiles = useCallback(() => { + setFormState({ status: 'pending' }); + resetValidation(); + const uploadFiles = formFiles.map((formFile) => { + const formData = new FormData(); + formData.append('file', formFile.file); + const document = pick(formFile, ['documentTypeId']); + + return apiIus.uploadDocument({ + document, + formData, + pageUrlParams, + }); + }); + + return Promise.allSettled(uploadFiles).catch(() => { + setFormState({ status: 'error', text: ERROR_UPLOAD_DOCUMENT }); + throw new Error(ERROR_UPLOAD_DOCUMENT); + }); + }, [formFiles, pageUrlParams, resetValidation, setFormState]); + + const handleRetract = useCallback(() => { + setFormState({ status: 'pending' }); + resetValidation(); + apiIus.retract({ pageUrlParams, payload: values }).then((res) => { + if (typeof res !== 'boolean') { + setTimeout(() => { + setFormState({ status: 'edit' }); + }, 300); + Object.keys(res.errors).forEach((name) => { + const elementValidation = res?.errors?.[name]; + if (elementValidation) + setValidation({ message: elementValidation[0] ?? '', name, valid: false }); + }); + } else { + setFormState({ status: 'success' }); + setTimeout(() => { + router.refresh(); + }, 500); + } + }); + }, [pageUrlParams, resetValidation, router, setFormState, setValidation, values]); + return (
- - +
); } diff --git a/apps/web/components/Form/Files.tsx b/apps/web/components/Form/Files.tsx new file mode 100644 index 0000000..f74fb52 --- /dev/null +++ b/apps/web/components/Form/Files.tsx @@ -0,0 +1,38 @@ +import { FormContext } from './context/form-context'; +import type { Props } from './types'; +import type { Document } from '@/api/ius/types'; +import { useContext } from 'react'; +import { Heading, InputFile } from 'ui'; + +function File({ documentTypeId, name }: Document) { + const { formFiles, setFormFiles } = useContext(FormContext); + + const handleFileChange = (event: React.ChangeEvent) => { + if (event.target.files) { + setFormFiles([ + ...formFiles.filter((x) => x.documentTypeId !== documentTypeId), + { documentTypeId, file: event.target.files[0], name }, + ]); + } + }; + + return ( +
+ + +
+ ); +} + +export function Files({ documentTypes }: Props) { + return ( +
+ Документы +
+ {documentTypes.map((document) => ( + + ))} +
+
+ ); +} diff --git a/apps/web/components/Form/Overlay.tsx b/apps/web/components/Form/Overlay.tsx index cf674b9..bf0545a 100644 --- a/apps/web/components/Form/Overlay.tsx +++ b/apps/web/components/Form/Overlay.tsx @@ -1,6 +1,6 @@ 'use client'; import { FormContext } from './context/form-context'; -import { CheckCircleIcon } from '@heroicons/react/24/solid'; +import { CheckCircleIcon, XCircleIcon } from '@heroicons/react/24/solid'; import type { PropsWithChildren } from 'react'; import { useContext } from 'react'; import { Background, LoadingSpinner } from 'ui'; @@ -15,21 +15,30 @@ function OverlayWrapper({ children }: PropsWithChildren) { ); } export function Overlay() { - const { formStatus } = useContext(FormContext); + const { formState } = useContext(FormContext); + const { status, text } = formState; - if (formStatus === 'pending') + if (status === 'pending') return ( {LoadingSpinner}

Загрузка...

); - if (formStatus === 'success') + if (status === 'success') return ( {' '}

Данные сохранены

); + if (status === 'error') { + return ( + + {' '} +

{text}

+
+ ); + } return false; } diff --git a/apps/web/components/Form/context/form-context.tsx b/apps/web/components/Form/context/form-context.tsx index d3ce6fc..4747dd2 100644 --- a/apps/web/components/Form/context/form-context.tsx +++ b/apps/web/components/Form/context/form-context.tsx @@ -1,13 +1,19 @@ +import type { Document } from '@/api/ius/types'; import type { PageUrlParams } from '@/utils/url'; import type { PropsWithChildren } from 'react'; import { createContext, useMemo, useState } from 'react'; -type FormStatus = 'pending' | 'edit' | 'success'; +type FormStatus = 'pending' | 'edit' | 'success' | 'error'; +type FormState = { status: FormStatus; text?: string }; + +type FormFile = Document & { file: File }; type ContextType = { - readonly formStatus: FormStatus; + readonly formFiles: FormFile[]; + readonly formState: FormState; readonly pageUrlParams: PageUrlParams; - readonly setFormStatus: (status: FormStatus) => void; + readonly setFormFiles: (files: FormFile[]) => void; + readonly setFormState: (formState: FormState) => void; }; export const FormContext = createContext({} as ContextType); @@ -16,10 +22,11 @@ export function FormContextProvider({ children, ...initialData }: PropsWithChildren & Pick) { - const [formStatus, setFormStatus] = useState('edit'); + const [formState, setFormState] = useState({ status: 'edit' }); + const [formFiles, setFormFiles] = useState([]); const value = useMemo( - () => ({ ...initialData, formStatus, setFormStatus }), - [formStatus, initialData] + () => ({ ...initialData, formFiles, formState, setFormFiles, setFormState }), + [formFiles, formState, initialData] ); return {children}; diff --git a/apps/web/components/Form/index.tsx b/apps/web/components/Form/index.tsx index dded0db..3cb4a0c 100644 --- a/apps/web/components/Form/index.tsx +++ b/apps/web/components/Form/index.tsx @@ -2,6 +2,7 @@ import { Buttons } from './Buttons'; import { FormContext, FormContextProvider } from './context/form-context'; import { Elements } from './Elements'; +import { Files } from './Files'; import { Header } from './Header'; import { Overlay } from './Overlay'; import type { Props } from './types'; @@ -20,6 +21,8 @@ function Content(props: Props) {
+ + ); diff --git a/apps/web/components/Form/types.ts b/apps/web/components/Form/types.ts index d35eaaf..86fc6e6 100644 --- a/apps/web/components/Form/types.ts +++ b/apps/web/components/Form/types.ts @@ -1,9 +1,10 @@ -import type { ResponseGetData, ResponseMetaData } from '@/api/ius/types'; +import type * as IUS from '@/api/ius/types'; import type { PageUrlParams } from '@/utils/url'; export type Props = { - readonly data: ResponseGetData; - readonly metaData: ResponseMetaData; + readonly data: IUS.ResponseGetData; + documentTypes: IUS.ResponseDocumentTypes; + readonly metaData: IUS.ResponseMetaData; readonly pageUrlParams: PageUrlParams; readonly title: string; }; diff --git a/apps/web/next.config.js b/apps/web/next.config.js index 4465f25..7056ce2 100644 --- a/apps/web/next.config.js +++ b/apps/web/next.config.js @@ -24,7 +24,7 @@ const nextConfig = { outputFileTracingRoot: path.join(__dirname, '../../'), }, reactStrictMode: true, - transpilePackages: ['ui'], + transpilePackages: ['ui', 'radash'], async rewrites() { return [ { diff --git a/apps/web/package.json b/apps/web/package.json index 5eb0b9b..55e047d 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -10,7 +10,8 @@ }, "dependencies": { "@heroicons/react": "^2.0.18", - "next": "^14.0.1", + "next": "^14.0.3", + "radash": "^11.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", "tsconfig": "*", diff --git a/apps/web/types/page.ts b/apps/web/types/page.ts index 40d21f5..e7ce788 100644 --- a/apps/web/types/page.ts +++ b/apps/web/types/page.ts @@ -1,4 +1,4 @@ export type PageProps = { params: { slug: string }; - searchParams: string | string[][] | Record; + searchParams: Record; }; diff --git a/apps/web/utils/url.ts b/apps/web/utils/url.ts index 28d9187..5eb33ff 100644 --- a/apps/web/utils/url.ts +++ b/apps/web/utils/url.ts @@ -1,7 +1,7 @@ import type { PageProps } from '@/types/page'; export function getPageUrlParams({ params, searchParams }: PageProps) { - return { path: `/${params.slug}`, urlSearchParams: new URLSearchParams(searchParams) }; + return { path: `/${params.slug}`, urlSearchParams: searchParams }; } export type PageUrlParams = ReturnType; diff --git a/packages/ui/input.tsx b/packages/ui/input.tsx index 8c9120c..ca070be 100644 --- a/packages/ui/input.tsx +++ b/packages/ui/input.tsx @@ -21,3 +21,15 @@ export const Input = forwardRef( export const InputNumber = forwardRef((props, ref) => ( )); + +export const InputFile = forwardRef((props, ref) => ( + +)); diff --git a/yarn.lock b/yarn.lock index 259975d..9b111f8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -574,10 +574,10 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@next/env@14.0.1": - version "14.0.1" - resolved "https://registry.yarnpkg.com/@next/env/-/env-14.0.1.tgz#7d03c9042c205a320aef2ea3f83c2d16b6825563" - integrity sha512-Ms8ZswqY65/YfcjrlcIwMPD7Rg/dVjdLapMcSHG26W6O67EJDF435ShW4H4LXi1xKO1oRc97tLXUpx8jpLe86A== +"@next/env@14.0.3": + version "14.0.3" + resolved "https://registry.yarnpkg.com/@next/env/-/env-14.0.3.tgz#9a58b296e7ae04ffebce8a4e5bd0f87f71de86bd" + integrity sha512-7xRqh9nMvP5xrW4/+L0jgRRX+HoNRGnfJpD+5Wq6/13j3dsdzxO3BCXn7D3hMqsDb+vjZnJq+vI7+EtgrYZTeA== "@next/eslint-plugin-next@^13.5.4": version "13.5.6" @@ -586,50 +586,50 @@ dependencies: glob "7.1.7" -"@next/swc-darwin-arm64@14.0.1": - version "14.0.1" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.0.1.tgz#75a5f872c4077ecd536d7496bc24f3d312d5dcd0" - integrity sha512-JyxnGCS4qT67hdOKQ0CkgFTp+PXub5W1wsGvIq98TNbF3YEIN7iDekYhYsZzc8Ov0pWEsghQt+tANdidITCLaw== +"@next/swc-darwin-arm64@14.0.3": + version "14.0.3" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.0.3.tgz#b1a0440ffbf69056451947c4aea5b6d887e9fbbc" + integrity sha512-64JbSvi3nbbcEtyitNn2LEDS/hcleAFpHdykpcnrstITFlzFgB/bW0ER5/SJJwUPj+ZPY+z3e+1jAfcczRLVGw== -"@next/swc-darwin-x64@14.0.1": - version "14.0.1" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.0.1.tgz#7d8498fc680cc8b4d5181bee336818c63779bc5e" - integrity sha512-625Z7bb5AyIzswF9hvfZWa+HTwFZw+Jn3lOBNZB87lUS0iuCYDHqk3ujuHCkiyPtSC0xFBtYDLcrZ11mF/ap3w== +"@next/swc-darwin-x64@14.0.3": + version "14.0.3" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.0.3.tgz#48b527ef7eb5dbdcaf62fd107bc3a78371f36f09" + integrity sha512-RkTf+KbAD0SgYdVn1XzqE/+sIxYGB7NLMZRn9I4Z24afrhUpVJx6L8hsRnIwxz3ERE2NFURNliPjJ2QNfnWicQ== -"@next/swc-linux-arm64-gnu@14.0.1": - version "14.0.1" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.0.1.tgz#184286794e67bed192de7dbb10d7f040c996f965" - integrity sha512-iVpn3KG3DprFXzVHM09kvb//4CNNXBQ9NB/pTm8LO+vnnnaObnzFdS5KM+w1okwa32xH0g8EvZIhoB3fI3mS1g== +"@next/swc-linux-arm64-gnu@14.0.3": + version "14.0.3" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.0.3.tgz#0a36475a38b2855ab8ea0fe8b56899bc90184c0f" + integrity sha512-3tBWGgz7M9RKLO6sPWC6c4pAw4geujSwQ7q7Si4d6bo0l6cLs4tmO+lnSwFp1Tm3lxwfMk0SgkJT7EdwYSJvcg== -"@next/swc-linux-arm64-musl@14.0.1": - version "14.0.1" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.0.1.tgz#e8121b860ebc97a8d2a9113e5a42878430e749d5" - integrity sha512-mVsGyMxTLWZXyD5sen6kGOTYVOO67lZjLApIj/JsTEEohDDt1im2nkspzfV5MvhfS7diDw6Rp/xvAQaWZTv1Ww== +"@next/swc-linux-arm64-musl@14.0.3": + version "14.0.3" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.0.3.tgz#25328a9f55baa09fde6364e7e47ade65c655034f" + integrity sha512-v0v8Kb8j8T23jvVUWZeA2D8+izWspeyeDGNaT2/mTHWp7+37fiNfL8bmBWiOmeumXkacM/AB0XOUQvEbncSnHA== -"@next/swc-linux-x64-gnu@14.0.1": - version "14.0.1" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.0.1.tgz#cdc4276b11a10c892fd1cb7dd31e024064db9c3b" - integrity sha512-wMqf90uDWN001NqCM/auRl3+qVVeKfjJdT9XW+RMIOf+rhUzadmYJu++tp2y+hUbb6GTRhT+VjQzcgg/QTD9NQ== +"@next/swc-linux-x64-gnu@14.0.3": + version "14.0.3" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.0.3.tgz#594b747e3c8896b2da67bba54fcf8a6b5a410e5e" + integrity sha512-VM1aE1tJKLBwMGtyBR21yy+STfl0MapMQnNrXkxeyLs0GFv/kZqXS5Jw/TQ3TSUnbv0QPDf/X8sDXuMtSgG6eg== -"@next/swc-linux-x64-musl@14.0.1": - version "14.0.1" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.0.1.tgz#4a194a484ceb34fd370e8d1af571493859fb2542" - integrity sha512-ol1X1e24w4j4QwdeNjfX0f+Nza25n+ymY0T2frTyalVczUmzkVD7QGgPTZMHfR1aLrO69hBs0G3QBYaj22J5GQ== +"@next/swc-linux-x64-musl@14.0.3": + version "14.0.3" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.0.3.tgz#a02da58fc6ecad8cf5c5a2a96a7f6030ec7f6215" + integrity sha512-64EnmKy18MYFL5CzLaSuUn561hbO1Gk16jM/KHznYP3iCIfF9e3yULtHaMy0D8zbHfxset9LTOv6cuYKJgcOxg== -"@next/swc-win32-arm64-msvc@14.0.1": - version "14.0.1" - resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.0.1.tgz#71923debee50f98ef166b28cdb3ad7e7463e6598" - integrity sha512-WEmTEeWs6yRUEnUlahTgvZteh5RJc4sEjCQIodJlZZ5/VJwVP8p2L7l6VhzQhT4h7KvLx/Ed4UViBdne6zpIsw== +"@next/swc-win32-arm64-msvc@14.0.3": + version "14.0.3" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.0.3.tgz#bf2be23d3ba2ebd0d4a9376a31f783efdb677b48" + integrity sha512-WRDp8QrmsL1bbGtsh5GqQ/KWulmrnMBgbnb+59qNTW1kVi1nG/2ndZLkcbs2GX7NpFLlToLRMWSQXmPzQm4tog== -"@next/swc-win32-ia32-msvc@14.0.1": - version "14.0.1" - resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.0.1.tgz#b8f46da899c279fd65db76f0951849290c480ef9" - integrity sha512-oFpHphN4ygAgZUKjzga7SoH2VGbEJXZa/KL8bHCAwCjDWle6R1SpiGOdUdA8EJ9YsG1TYWpzY6FTbUA+iAJeww== +"@next/swc-win32-ia32-msvc@14.0.3": + version "14.0.3" + resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.0.3.tgz#839f8de85a4bf2c3c69242483ab87cb916427551" + integrity sha512-EKffQeqCrj+t6qFFhIFTRoqb2QwX1mU7iTOvMyLbYw3QtqTw9sMwjykyiMlZlrfm2a4fA84+/aeW+PMg1MjuTg== -"@next/swc-win32-x64-msvc@14.0.1": - version "14.0.1" - resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.0.1.tgz#be3dd8b3729ec51c99ff04b51e2b235756d02b6e" - integrity sha512-FFp3nOJ/5qSpeWT0BZQ+YE1pSMk4IMpkME/1DwKBwhg4mJLB9L+6EXuJi4JEwaJdl5iN+UUlmUD3IsR1kx5fAg== +"@next/swc-win32-x64-msvc@14.0.3": + version "14.0.3" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.0.3.tgz#27b623612b1d0cea6efe0a0d31aa1a335fc99647" + integrity sha512-ERhKPSJ1vQrPiwrs15Pjz/rvDHZmkmvbf/BjPN/UCOI++ODftT0GtasDPi0j+y6PPJi5HsXw+dpRaXUaw4vjuQ== "@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1": version "5.1.1-v1" @@ -4100,12 +4100,12 @@ netmask@^2.0.2: resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7" integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg== -next@^14.0.1: - version "14.0.1" - resolved "https://registry.yarnpkg.com/next/-/next-14.0.1.tgz#1375d94c5dc7af730234af48401be270e975cb22" - integrity sha512-s4YaLpE4b0gmb3ggtmpmV+wt+lPRuGtANzojMQ2+gmBpgX9w5fTbjsy6dXByBuENsdCX5pukZH/GxdFgO62+pA== +next@^14.0.3: + version "14.0.3" + resolved "https://registry.yarnpkg.com/next/-/next-14.0.3.tgz#8d801a08eaefe5974203d71092fccc463103a03f" + integrity sha512-AbYdRNfImBr3XGtvnwOxq8ekVCwbFTv/UJoLwmaX89nk9i051AEY4/HAWzU0YpaTDw8IofUpmuIlvzWF13jxIw== dependencies: - "@next/env" "14.0.1" + "@next/env" "14.0.3" "@swc/helpers" "0.5.2" busboy "1.6.0" caniuse-lite "^1.0.30001406" @@ -4113,15 +4113,15 @@ next@^14.0.1: styled-jsx "5.1.1" watchpack "2.4.0" optionalDependencies: - "@next/swc-darwin-arm64" "14.0.1" - "@next/swc-darwin-x64" "14.0.1" - "@next/swc-linux-arm64-gnu" "14.0.1" - "@next/swc-linux-arm64-musl" "14.0.1" - "@next/swc-linux-x64-gnu" "14.0.1" - "@next/swc-linux-x64-musl" "14.0.1" - "@next/swc-win32-arm64-msvc" "14.0.1" - "@next/swc-win32-ia32-msvc" "14.0.1" - "@next/swc-win32-x64-msvc" "14.0.1" + "@next/swc-darwin-arm64" "14.0.3" + "@next/swc-darwin-x64" "14.0.3" + "@next/swc-linux-arm64-gnu" "14.0.3" + "@next/swc-linux-arm64-musl" "14.0.3" + "@next/swc-linux-x64-gnu" "14.0.3" + "@next/swc-linux-x64-musl" "14.0.3" + "@next/swc-win32-arm64-msvc" "14.0.3" + "@next/swc-win32-ia32-msvc" "14.0.3" + "@next/swc-win32-x64-msvc" "14.0.3" no-case@^2.2.0, no-case@^2.3.2: version "2.3.2" @@ -4669,6 +4669,11 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +radash@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/radash/-/radash-11.0.0.tgz#925698e94b554336fc159c253ac33a9a49881835" + integrity sha512-CRWxTFTDff0IELGJ/zz58yY4BDgyI14qSM5OLNKbCItJrff7m7dXbVF0kWYVCXQtPb3SXIVhXvAImH6eT7VLSg== + rambda@^7.4.0: version "7.5.0" resolved "https://registry.yarnpkg.com/rambda/-/rambda-7.5.0.tgz#1865044c59bc0b16f63026c6e5a97e4b1bbe98fe"