feature/create-place #8

Merged
behnam merged 5 commits from feature/create-place into develop 2023-05-30 13:07:57 +00:00
33 changed files with 868 additions and 93 deletions

View File

@ -3,3 +3,5 @@
npm run test && npm run lint
npm run test && npm run lint
npm run test && npm run lint
npm run test && npm run lint

View File

@ -14,12 +14,14 @@
},
"dependencies": {
"@reduxjs/toolkit": "^1.9.3",
"@types/react-select": "^5.0.1",
"axios": "^1.3.4",
"qrcode.react": "^3.1.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-redux": "^8.0.5",
"react-router-dom": "^6.9.0",
"react-select": "^5.7.3",
"swr": "^2.1.5"
},
"devDependencies": {

View File

@ -0,0 +1,11 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 1024 1024" class="icon" xmlns="http://www.w3.org/2000/svg" fill="#fff" stroke="#fff">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
<g id="SVGRepo_iconCarrier">
<path fill="#fff" d="M288 896h448q32 0 32 32t-32 32H288q-32 0-32-32t32-32z"/>
<path fill="#fff" d="M800 416a288 288 0 10-576 0c0 118.144 94.528 272.128 288 456.576C705.472 688.128 800 534.144 800 416zM512 960C277.312 746.688 160 565.312 160 416a352 352 0 01704 0c0 149.312-117.312 330.688-352 544z"/>
<path fill="#fff" d="M544 384h96a32 32 0 110 64h-96v96a32 32 0 01-64 0v-96h-96a32 32 0 010-64h96v-96a32 32 0 0164 0v96z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 915 B

View File

@ -1,7 +1,7 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M14 2H6C5.46957 2 4.96086 2.21071 4.58579 2.58579C4.21071 2.96086 4 3.46957 4 4V20C4 20.5304 4.21071 21.0391 4.58579 21.4142C4.96086 21.7893 5.46957 22 6 22H18C18.5304 22 19.0391 21.7893 19.4142 21.4142C19.7893 21.0391 20 20.5304 20 20V8L14 2Z" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M14 2V8H20" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M16 13H8" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M16 17H8" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M10 9H9H8" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg fill="#fff" width="197px" height="197px" viewBox="-2.08 -2.08 20.16 20.16" id="add-user-16px" xmlns="http://www.w3.org/2000/svg" stroke="#fff">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>
<g id="SVGRepo_iconCarrier"> <path id="Path_179" data-name="Path 179" d="M29.991,8a4,4,0,1,0-4-4A4,4,0,0,0,29.991,8Zm0-7a3,3,0,1,1-3,3A3,3,0,0,1,29.991,1ZM31,15.5a.5.5,0,0,1-.5.5h-7A1.5,1.5,0,0,1,22,14.5,4.505,4.505,0,0,1,26.5,10h4a.5.5,0,0,1,0,1h-4A3.5,3.5,0,0,0,23,14.5a.5.5,0,0,0,.5.5h7A.5.5,0,0,1,31,15.5Zm7-3a.5.5,0,0,1-.5.5H35v2.5a.5.5,0,0,1-1,0V13H31.5a.5.5,0,0,1,0-1H34V9.5a.5.5,0,0,1,1,0V12h2.5A.5.5,0,0,1,38,12.5Z" transform="translate(-22)"/> </g>
</svg>

Before

Width:  |  Height:  |  Size: 841 B

After

Width:  |  Height:  |  Size: 928 B

View File

@ -7,7 +7,7 @@ const getPlacesRO = (placesResponse: GetPlacesResponse): GetPlacesRO => {
id: placeResponse._id,
placeType: placeResponse.place_type,
name: placeResponse.name,
parentId: placeResponse.place_type,
parentId: placeResponse.parent_id,
availableServices: placeResponse.available_services,
createdAt: placeResponse.createdAt,
updatedAt: placeResponse.updatedAt,

View File

@ -0,0 +1,45 @@
import AdminUserModel from '~/business-logic/generic/admin-user/common/data/model/adminUserModel';
import { HTTPPovider } from '~/driven/boundaries/http-boundary/httpBoundary';
import { HttpOptionsType } from '~/driven/boundaries/http-boundary/protocols';
import { apiUrls } from '~/driven/utils/configs/appConfig';
import {
ICreatePlaceLogicMaker,
createPlaceArguments,
} from '~/driving/application/core/places/create-place/model/submiCreatePlace';
const createPlacesDto = (newPlace: createPlaceArguments) => ({
place_type: newPlace.placeType,
parent_id: newPlace.parentId || null,
name: newPlace.placeName,
});
const createPlaceAdapter = (
userAdmin: AdminUserModel | null,
updateAccessToken: (newAccessToken: string) => void,
navigateToAuth: () => void,
): ICreatePlaceLogicMaker => {
const url = apiUrls.core.createPlace;
const httpHandler = async (newPlace: createPlaceArguments) => {
const httpProvider = new HTTPPovider(
{
accessToken: (userAdmin && userAdmin?.adminUserData.accessToken) || null,
refreshToken: (userAdmin && userAdmin?.adminUserData.refreshToken) || null,
},
updateAccessToken,
navigateToAuth,
);
const dto = createPlacesDto(newPlace);
const options: HttpOptionsType = {
url,
method: 'POST',
data: dto,
};
return await httpProvider.request<string>(options);
};
return {
httpHandler,
};
};
export default createPlaceAdapter;

View File

@ -46,7 +46,6 @@ export class HTTPPovider {
async request<R>(customOptions: HttpOptionsType) {
const axiosInstance = this.handleRequestInterceptor();
this.responseIncepter(axiosInstance);
const response = await axiosInstance<ApiGlobalResponseObject<R>>(customOptions);
if (!response) throw new Error(staticMessages.service.errors[500]);

View File

@ -10,6 +10,9 @@ export default class SwrBoundary implements StateManagementProvider {
isLoading: boolean;
error?: string | undefined;
} {
return useSwr(key, httpHandler);
return useSwr(key, httpHandler, {
revalidateOnFocus: false,
errorRetryCount: 3,
});
}
}

View File

@ -0,0 +1,18 @@
import React, { PropsWithChildren } from 'react';
export interface IInputWrapper {
title: string;
className?: string;
}
export default function InputWrapper(props: PropsWithChildren<IInputWrapper>) {
const { children, title, className } = props;
return (
<div className={`flex flex-col ${className}`}>
<label className='mb-1 text-txt-second text-xs' htmlFor={title}>
{title}
</label>
{children}
</div>
);
}

View File

@ -0,0 +1,34 @@
/* eslint-disable import/no-extraneous-dependencies */
import React from 'react';
import Select from 'react-select';
import InputWrapper, { IInputWrapper } from '../input-wrapper/InputWrapper';
interface IInputBox<ValueType> extends IInputWrapper {
name: string;
state: {
value: { value: ValueType; label: string };
options: { value: ValueType; label: string }[];
setValue: (newValue: ValueType, label: string) => void;
isLoading?: boolean;
};
}
export default function InputBox<ValueType>(props: IInputBox<ValueType>) {
const { title, className, name, state } = props;
const { setValue, value, options } = state;
return (
<InputWrapper title={title} className={className}>
<Select
classNamePrefix='select'
defaultValue={value}
value={value}
isLoading={state.isLoading}
onChange={(newValue) => newValue && newValue.value && setValue(newValue.value, newValue.label)}
isSearchable
name={name}
options={options}
className='text-txt-medium'
/>
</InputWrapper>
);
}

View File

@ -1,4 +1,5 @@
import React from 'react';
import InputWrapper from '../input-wrapper/InputWrapper';
export type SetStateInputMethod<NameType> = (name: NameType, newValue: string) => void;
@ -25,10 +26,7 @@ export default function SimpleInput<NameType>(props: ISimpleInput<NameType>) {
};
return (
<div className={`flex flex-col ${className}`}>
<label className='mb-1 text-txt-second text-xs' htmlFor={title}>
{title}
</label>
<InputWrapper title={title} className={className}>
<input
value={state}
onChange={handleInputChange}
@ -36,6 +34,6 @@ export default function SimpleInput<NameType>(props: ISimpleInput<NameType>) {
className='bg-bg-gray h-11 rounded-lg focus:outline-0 px-2 text-txt-medium w-full'
id={title}
/>
</div>
</InputWrapper>
);
}

View File

@ -9,6 +9,7 @@ export const appConfig = {
export const routes = {
usersList: '/',
createUser: '/create-user',
createPlace: '/create-place',
authentication: '/auth',
};
@ -23,6 +24,11 @@ export const routesData = {
icon: icons.createUser,
title: staticMessages.global.createUser,
},
createPlace: {
path: routes.createPlace,
icon: icons.createPlace,
title: staticMessages.global.createPlace,
},
};
const baseApiUrl = ENVs.apiOrigin;
@ -34,6 +40,7 @@ export const apiUrls = {
createUserAccount: `${baseApiUrl}${ENVs.apiCreateUserAccount}`,
createUserProfile: `${baseApiUrl}${ENVs.apiCreateUserProfile}`,
createMember: `${baseApiUrl}${ENVs.apiCreateMember}`,
createPlace: `${baseApiUrl}${ENVs.apiCreatePlace}`,
},
generic: {
authPhonenumber: `${ENVs.apiAuthOrigin}${ENVs.apiAuthPhonenumber}`,

View File

@ -5,5 +5,6 @@ export const icons = {
logoBlack: `${baseIconsUrl}logo-black.svg`,
users: `${baseIconsUrl}users.svg`,
createUser: `${baseIconsUrl}createuser.svg`,
createPlace: `${baseIconsUrl}createplace.svg`,
qrcode: `${baseIconsUrl}qrcode.png`,
};

View File

@ -10,4 +10,5 @@ export const ENVs = {
apiQr: process.env.VITE_API_QR,
apiCreateUserProfile: process.env.VITE_API_USERS_PROFILE,
apiCreateMember: process.env.VITE_API_CREATE_MEMBER,
apiCreatePlace: process.env.VITE_API_PLACES,
};

View File

@ -4,6 +4,7 @@ export const staticMessages = {
input: 'please fill all inputs correctly',
phonenumber: 'please fill the valid number',
otp: 'please fill the otp fields correctly',
inputPlace: 'place type and name of place is necessary',
},
users: 'Users',
submit: 'Submit',
@ -13,9 +14,12 @@ export const staticMessages = {
title: 'title',
status: 'Status',
placeType: 'Place Type',
placeParentId: 'Parent id',
address: 'Address',
qrCode: 'qrCode',
createUser: 'Create user',
createPlace: 'Create place',
PlaceName: 'Place name',
phonenumber: 'Phone Number',
enterPanel: 'Enter to Panel',
enterPhoneNumber: 'Enter your phone number',
@ -23,15 +27,29 @@ export const staticMessages = {
success: {
createUser: 'user created successfully',
createMember: 'member created successfully',
createPlace: 'place created successfully',
},
and: 'and',
canUseFor: 'can use for',
oneTime: 'one time',
multipleTimes: 'multiple times',
},
placeTypes: {
continent: 'Continent',
country: 'Country',
state: 'State',
region: 'Region',
city: 'City',
district: 'District',
street: 'Street',
building: 'Building',
section: 'Section',
floor: 'Floor',
flat: 'Flat',
},
service: {
errors: {
500: 'server not respond please try again later!',
500: 'there is a problem with connecting to the server please try again later!',
401: 'Authentication error!',
},
},

View File

@ -0,0 +1,79 @@
/* eslint-disable consistent-return */
/* eslint-disable no-underscore-dangle */
import { QrPlace } from '~/business-logic/core/places/common/entity/placeEntity';
import getPlaces from '~/business-logic/core/places/get-places';
import AdminUserModel from '~/business-logic/generic/admin-user/common/data/model/adminUserModel';
import getPlacesAdapter from '~/driven/adapters/get-places-adapter/getPlacesAdapter';
import { HTTPPovider } from '~/driven/boundaries/http-boundary/httpBoundary';
import { HttpOptionsType } from '~/driven/boundaries/http-boundary/protocols';
import { apiUrls } from '~/driven/utils/configs/appConfig';
import useGetNavigatorAndTokenUpdater from '~/driven/utils/helpers/hooks/getNavigatorAndAccessTokenUpdator';
import { prepareStateManagementForVM } from '~/driven/utils/helpers/globalHelpers';
import PlacesModel from '~/business-logic/core/places/common/model/placesModel';
import placesListModel from '../../places-list/model/placesListModel';
type QrCodeResponse = {
one_time: false;
place_id: string;
user_id: string;
_id: string;
}[];
const QrCodeRO = (response: QrCodeResponse): QrPlace[] => {
return response.map((qrCode) => ({
id: qrCode._id,
oneTime: qrCode.one_time,
placeId: qrCode.place_id,
userId: qrCode.user_id,
}));
};
const prepareTheLogicForModel = () => {
const { accessTokenUpdateHandler, notLoginAuth, userData } = useGetNavigatorAndTokenUpdater();
const { user } = userData;
const gettingPlacesDrivenAdapter = getPlacesAdapter(user as AdminUserModel, accessTokenUpdateHandler, notLoginAuth);
const { url } = gettingPlacesDrivenAdapter;
const getingPlacesLogic = getPlaces(gettingPlacesDrivenAdapter);
return { getingPlacesLogic, url };
};
const useGetPlaceList = () => {
const { accessTokenUpdateHandler, notLoginAuth, userData } = useGetNavigatorAndTokenUpdater();
const getQrCodes = async () => {
try {
// url
const apiUrl = apiUrls.core.getQrs;
// options
const apiOptions: HttpOptionsType = {
url: apiUrl,
};
// request
const userToken = {
accessToken: userData.user?.adminUserData.accessToken || null,
refreshToken: userData.user?.adminUserData.refreshToken || null,
};
const httpProvider = new HTTPPovider(userToken, accessTokenUpdateHandler, notLoginAuth);
const response = await httpProvider.request<QrCodeResponse>(apiOptions);
const qrCodeList = QrCodeRO(response);
return qrCodeList;
// update the query
} catch (error) {
console.log(error);
}
};
const { getingPlacesLogic, url } = prepareTheLogicForModel();
const getPlacesWithQrLogic = async () => {
const placesList = await getingPlacesLogic();
const qrCodesList = await getQrCodes();
placesList.setQrFor(qrCodesList || []);
return placesList;
};
const placesModel = async () => await placesListModel(getPlacesWithQrLogic);
const useGetPlacesList = prepareStateManagementForVM<PlacesModel>(url, placesModel);
return useGetPlacesList;
};
export default useGetPlaceList;

View File

@ -0,0 +1,3 @@
import CreatePlace from './infra/CreatePlace';
export default CreatePlace;

View File

@ -0,0 +1,30 @@
import React from 'react';
import createPlaceAdapter from '~/driven/adapters/create-place-adapter/createPlaceAdapter';
import useGetNavigatorAndTokenUpdater from '~/driven/utils/helpers/hooks/getNavigatorAndAccessTokenUpdator';
import CreatePlaceView from '../view/CreatePlaceView';
import useCreatePlaceVm from '../viewmodel/createPlaceVM';
import createPlaceModel from '../model/createPlaceModel';
export default function CreatePlace() {
const { accessTokenUpdateHandler, notLoginAuth, userData } = useGetNavigatorAndTokenUpdater();
const { user } = userData;
const createPlaceDrivenAdapter = createPlaceAdapter(user, accessTokenUpdateHandler, notLoginAuth);
const { inputOptions, createPlace } = createPlaceModel(createPlaceDrivenAdapter);
const { formStateData, inputStateHandlers, selectBoxOptions, handleSubmitCreatePlaceForm } = useCreatePlaceVm({
getInputOptions: inputOptions,
createPlaceModel: createPlace,
});
return (
<CreatePlaceView
handleSubmitCreatePlaceForm={handleSubmitCreatePlaceForm}
inputOptions={{
parentId: selectBoxOptions.parentIdsOptions,
placeType: selectBoxOptions.placeTypesOptions,
isParentIdLoading: selectBoxOptions.isParentIdLoading,
}}
formStateData={formStateData}
inputStateHandlers={inputStateHandlers}
/>
);
}

View File

@ -0,0 +1,20 @@
import { CreatePlaceType } from './protocols';
import getValidOptionsOfSelectBox from './getValidOptionsOfSelectBox';
import createPlaceLogicMaker, { ICreatePlaceLogicMaker } from './submiCreatePlace';
type ICreatePlaceModel = ICreatePlaceLogicMaker;
const createPlaceModel = (depenedencies: ICreatePlaceModel): CreatePlaceType => {
const { getPlacesTypeOptionsOfSelectBox, getValidParentIdsOptionsOfSelectBox } = getValidOptionsOfSelectBox;
const { createPlace } = createPlaceLogicMaker(depenedencies);
return {
createPlace,
inputOptions: {
getPlaceType: getPlacesTypeOptionsOfSelectBox,
getParentIds: getValidParentIdsOptionsOfSelectBox,
},
};
};
export default createPlaceModel;

View File

@ -0,0 +1,66 @@
import Places from '~/business-logic/core/places/common/entity/placeEntity';
import PlacesModel from '~/business-logic/core/places/common/model/placesModel';
import { staticMessages } from '~/driven/utils/constants/staticMessages';
import { placeTypes } from '../view/protocol';
export const placeTypeTuple: ReadonlyArray<`${placeTypes}`> = [
placeTypes.continent,
placeTypes.country,
placeTypes.state,
placeTypes.region,
placeTypes.city,
placeTypes.district,
placeTypes.street,
placeTypes.building,
placeTypes.section,
placeTypes.floor,
placeTypes.flat,
];
const makeOptionsOfSelectBoxForParentIds = (places: Places[], currentPlaceType: `${placeTypes}`) => {
const currentPlaceTypeIndex = placeTypeTuple.indexOf(currentPlaceType);
if (currentPlaceTypeIndex === -1) throw new Error();
const placesValidToShow = places.reduce((prevVal, currentVal) => {
const placeListItemIndex = placeTypeTuple.indexOf(currentVal.placeType as `${placeTypes}`);
if (!currentVal.parentId) return prevVal;
if (placeListItemIndex === -1) return prevVal;
if (placeListItemIndex > currentPlaceTypeIndex) return prevVal;
const label = `${currentVal.placeType} ${currentVal.name}`;
return [...prevVal, { value: currentVal.parentId, label }];
}, <{ value: string; label: string }[]>[]);
return placesValidToShow;
};
const getValidParentIdsOptionsOfSelectBox = (
currentPlaceType: `${placeTypes}`,
placesList: PlacesModel,
): { value: string; label: string }[] => {
try {
if (!placesList) throw new Error();
const places = placesList.getData();
if (!places.length) throw new Error();
const placesOptionsValidToShow = makeOptionsOfSelectBoxForParentIds(places, currentPlaceType);
return placesOptionsValidToShow;
} catch (_error) {
return [];
}
};
const getPlacesTypeOptionsOfSelectBox = () => {
return Object.keys(placeTypes).map((placeTypeKey) => {
const key = placeTypeKey as keyof typeof placeTypes;
return { value: placeTypes[key], label: staticMessages.placeTypes[placeTypes[key]] };
});
};
export default {
getValidParentIdsOptionsOfSelectBox,
getPlacesTypeOptionsOfSelectBox,
};

View File

@ -0,0 +1,3 @@
import createPlaceModel from './createPlaceModel';
export default createPlaceModel;

View File

@ -0,0 +1,20 @@
import PlacesModel from '~/business-logic/core/places/common/model/placesModel';
import { placeTypes } from '../view/protocol';
import { createPlaceArguments } from './submiCreatePlace';
export type CreatePlaceType = {
createPlace: (placeData: createPlaceArguments) => Promise<string>;
inputOptions: {
getPlaceType: () => {
value: placeTypes;
label: string;
}[];
getParentIds: (
currentPlaceType: `${placeTypes}`,
placesList: PlacesModel,
) => {
value: string;
label: string;
}[];
};
};

View File

@ -0,0 +1,24 @@
import { placeTypes } from '../view/protocol';
export type createPlaceArguments = {
placeType: `${placeTypes}`;
placeName: string;
parentId: string;
};
export interface ICreatePlaceLogicMaker {
httpHandler: (placeData: createPlaceArguments) => Promise<string>;
}
const createPlaceLogicMaker = (depenedencies: ICreatePlaceLogicMaker) => {
const { httpHandler } = depenedencies;
const createPlace = async (placeData: createPlaceArguments) => {
return await httpHandler(placeData);
};
return {
createPlace,
};
};
export default createPlaceLogicMaker;

View File

@ -0,0 +1,61 @@
import React from 'react';
import SimpleInput from '~/driven/utils/components/inputs/simple-input/SimpleInput';
import InputBox from '~/driven/utils/components/inputs/select-box/InputBox';
import { staticMessages } from '~/driven/utils/constants/staticMessages';
import PrimaryButton from '~/driven/utils/components/buttons/primary-button/PrimaryButton';
import Notification from '~/driven/utils/components/Notification/Notification';
import { ICreatePlaceProps } from './protocol';
export default function CreatePlaceView(props: ICreatePlaceProps) {
const { formStateData, inputStateHandlers, inputOptions, handleSubmitCreatePlaceForm } = props;
const { formState, error, setError } = formStateData;
return (
<>
{Boolean(error.message) && (
<Notification
message={error.message}
type={error.type}
onCloseCallback={() => setError({ message: '', type: 'error' })}
/>
)}
<form onSubmit={handleSubmitCreatePlaceForm} className='p-4 py-6 flex flex-wrap w-full gap-4'>
<SimpleInput
inputData={{
name: staticMessages.global.PlaceName,
title: staticMessages.global.PlaceName,
}}
stateHanlder={{
state: formState.placeName,
setState: inputStateHandlers.name,
}}
className='mb-4 w-[48%] px-2'
/>
<InputBox
name={staticMessages.global.placeType}
state={{
value: { value: formState.placeTypes, label: staticMessages.placeTypes[formState.placeTypes] },
setValue: inputStateHandlers.placeType,
options: inputOptions.placeType,
}}
title={staticMessages.global.placeType}
className='mb-4 w-[48%] px-2 border-1 border-txt-medium text-txt-medium'
/>
<InputBox
name={staticMessages.global.placeParentId}
state={{
value: { value: formState.parentId.value, label: formState.parentId.label },
setValue: inputStateHandlers.parentId,
options: inputOptions.parentId,
isLoading: inputOptions.isParentIdLoading,
}}
title={staticMessages.global.placeParentId}
className='mb-4 w-[48%] px-2 border-1 border-txt-medium text-txt-medium'
/>
<div className='w-full'>
<PrimaryButton onClick={() => null} title={staticMessages.global.submit} />
</div>
</form>
</>
);
}

View File

@ -0,0 +1,53 @@
export enum placeTypes {
continent = 'continent',
country = 'country',
state = 'state',
region = 'region',
city = 'city',
district = 'district',
street = 'street',
building = 'building',
section = 'section',
floor = 'floor',
flat = 'flat',
}
export type PlaceFormState = {
placeName: string;
placeTypes: `${placeTypes}`;
parentId: { value: string; label: string };
};
export interface ICreatePlaceProps {
handleSubmitCreatePlaceForm: (e: React.FormEvent) => Promise<void>;
formStateData: {
formState: PlaceFormState;
error: {
message: string;
type: 'error' | 'success';
};
setError: React.Dispatch<
React.SetStateAction<{
message: string;
type: 'error' | 'success';
}>
>;
setFormState: React.Dispatch<React.SetStateAction<PlaceFormState>>;
};
inputStateHandlers: {
name: (_name: string, newValue: string) => void;
placeType: (newValue: `${placeTypes}`) => void;
parentId: (newValue: string, label: string) => void;
};
inputOptions: {
placeType: {
value: placeTypes;
label: string;
}[];
parentId: {
value: string;
label: string;
}[];
isParentIdLoading: boolean;
};
}

View File

@ -0,0 +1,97 @@
import { useCallback, useEffect, useMemo, useState } from 'react';
import { AxiosError } from 'axios';
import { staticMessages } from '~/driven/utils/constants/staticMessages';
import useGetPlaceList from '../../common/hooks/useGetPlaceList';
import { PlaceFormState, placeTypes } from '../view/protocol';
import { createPlaceArguments } from '../model/submiCreatePlace';
import { ICreatePlaceVm, initialPlaceFormState } from './protocols';
const onChangeInputStateHandlers = (setFormState: React.Dispatch<React.SetStateAction<PlaceFormState>>) => {
const handleNameSetState = (_name: string, newValue: string) =>
setFormState((prev) => ({ ...prev, placeName: newValue }));
const handlePlaceTypeSetState = (newValue: `${placeTypes}`) =>
setFormState((prev) => ({ ...prev, placeTypes: newValue }));
const handleParentIdSetState = (newValue: string, label: string) =>
setFormState((prev) => ({ ...prev, parentId: { value: newValue, label } }));
return {
handleNameSetState,
handlePlaceTypeSetState,
handleParentIdSetState,
};
};
const resetParentIdOnChangePlaceType = (setFormState: React.Dispatch<React.SetStateAction<PlaceFormState>>) => {
setFormState((prev) => ({ ...prev, parentId: { label: '', value: '' } }));
};
const useCreatePlaceVm = (dependencies: ICreatePlaceVm) => {
const { getInputOptions, createPlaceModel } = dependencies;
const { getParentIds, getPlaceType } = getInputOptions;
const [formState, setFormState] = useState<PlaceFormState>(initialPlaceFormState);
const [error, setError] = useState<{ message: string; type: 'error' | 'success' }>({ message: '', type: 'error' });
const { handleNameSetState, handleParentIdSetState, handlePlaceTypeSetState } = useMemo(
() => onChangeInputStateHandlers(setFormState),
[],
);
const handleSubmitCreatePlaceForm = async (e: React.FormEvent) => {
e.preventDefault();
try {
const { parentId, placeName, placeTypes: placeType } = formState;
if (!placeName || !placeName) throw new Error(staticMessages.global.errors.inputPlace);
const newPlaceData: createPlaceArguments = {
parentId: parentId.value,
placeName,
placeType,
};
const response = await createPlaceModel(newPlaceData);
if (!response) throw new Error(staticMessages.service.errors[500]);
setError({
message: staticMessages.global.success.createPlace,
type: 'success',
});
} catch (errorExc) {
if (errorExc instanceof AxiosError) {
setError({ message: errorExc.response?.data?.description, type: 'error' });
} else if (errorExc instanceof Error) {
setError({ message: errorExc.message, type: 'error' });
}
}
};
useEffect(() => resetParentIdOnChangePlaceType(setFormState), [formState.placeTypes]);
const getPlaceList = useCallback(() => useGetPlaceList()(), []);
const places = getPlaceList();
const placeTypesOptions = useMemo(() => getPlaceType(), []);
const parentIdsOptions = useMemo(() => {
if (!places.data) return [];
return getParentIds(formState.placeTypes, places.data);
}, [formState.placeTypes, places]);
return {
handleSubmitCreatePlaceForm,
formStateData: {
formState,
error,
setError,
setFormState,
},
inputStateHandlers: {
name: handleNameSetState,
parentId: handleParentIdSetState,
placeType: handlePlaceTypeSetState,
},
selectBoxOptions: {
placeTypesOptions,
parentIdsOptions,
isParentIdLoading: places.isLoading,
},
};
};
export default useCreatePlaceVm;

View File

@ -0,0 +1,14 @@
import { CreatePlaceType } from '../model/protocols';
import { createPlaceArguments } from '../model/submiCreatePlace';
import { PlaceFormState, placeTypes } from '../view/protocol';
export const initialPlaceFormState: PlaceFormState = {
placeTypes: placeTypes.continent,
placeName: '',
parentId: { value: '', label: '' },
};
export interface ICreatePlaceVm {
getInputOptions: CreatePlaceType['inputOptions'];
createPlaceModel: (placeData: createPlaceArguments) => Promise<string>;
}

View File

@ -1,44 +1,9 @@
/* eslint-disable consistent-return */
/* eslint-disable no-underscore-dangle */
import React from 'react';
import getPlaces from '~/business-logic/core/places/get-places';
import getPlacesAdapter from '~/driven/adapters/get-places-adapter/getPlacesAdapter';
import PlacesModel from '~/business-logic/core/places/common/model/placesModel';
import { prepareStateManagementForVM } from '~/driven/utils/helpers/globalHelpers';
import useGetNavigatorAndTokenUpdater from '~/driven/utils/helpers/hooks/getNavigatorAndAccessTokenUpdator';
import AdminUserModel from '~/business-logic/generic/admin-user/common/data/model/adminUserModel';
import { apiUrls } from '~/driven/utils/configs/appConfig';
import { HttpOptionsType } from '~/driven/boundaries/http-boundary/protocols';
import { HTTPPovider } from '~/driven/boundaries/http-boundary/httpBoundary';
import { QrPlace } from '~/business-logic/core/places/common/entity/placeEntity';
import PlacesListView from '../view/PlacesListView';
import usePlacesListVM from '../viewmodel/placesListVM';
import placesListModel from '../model/placesListModel';
type QrCodeResponse = {
one_time: false;
place_id: string;
user_id: string;
_id: string;
}[];
const QrCodeRO = (response: QrCodeResponse): QrPlace[] => {
return response.map((qrCode) => ({
id: qrCode._id,
oneTime: qrCode.one_time,
placeId: qrCode.place_id,
userId: qrCode.user_id,
}));
};
const prepareTheLogicForModel = () => {
const { accessTokenUpdateHandler, notLoginAuth, userData } = useGetNavigatorAndTokenUpdater();
const { user } = userData;
const gettingPlacesDrivenAdapter = getPlacesAdapter(user as AdminUserModel, accessTokenUpdateHandler, notLoginAuth);
const { url } = gettingPlacesDrivenAdapter;
const getingPlacesLogic = getPlaces(gettingPlacesDrivenAdapter);
return { getingPlacesLogic, url };
};
import useGetPlaceList from '../../common/hooks/useGetPlaceList';
export interface IPlacesListProps {
selectedRowId: string;
@ -47,40 +12,8 @@ export interface IPlacesListProps {
export default function PlacessList(props: IPlacesListProps) {
const { selectedRowId, setSelectedRowId } = props;
const { accessTokenUpdateHandler, notLoginAuth, userData } = useGetNavigatorAndTokenUpdater();
const getQrCodes = async () => {
try {
// url
const apiUrl = apiUrls.core.getQrs;
// options
const apiOptions: HttpOptionsType = {
url: apiUrl,
};
// request
const userToken = {
accessToken: userData.user?.adminUserData.accessToken || null,
refreshToken: userData.user?.adminUserData.refreshToken || null,
};
const httpProvider = new HTTPPovider(userToken, accessTokenUpdateHandler, notLoginAuth);
const response = await httpProvider.request<QrCodeResponse>(apiOptions);
const qrCodeList = QrCodeRO(response);
return qrCodeList;
// update the query
} catch (error) {
console.log(error);
}
};
const { getingPlacesLogic, url } = prepareTheLogicForModel();
const getPlacesWithQrLogic = async () => {
const placesList = await getingPlacesLogic();
const qrCodesList = await getQrCodes();
placesList.setQrFor(qrCodesList || []);
return placesList;
};
const placesModel = async () => await placesListModel(getPlacesWithQrLogic);
const useGetPlacesList = prepareStateManagementForVM<PlacesModel>(url, placesModel);
const useGetPlacesList = useGetPlaceList();
const { placesData } = usePlacesListVM({
useGetPlacesList,
});

View File

@ -2,7 +2,7 @@ import { INewUserData } from '~/business-logic/core/users/create-user/create-acc
import { SetStateInputMethod } from '~/driven/utils/components/inputs/simple-input/SimpleInput';
export default interface ICreateUserViewProps {
onSubmit: (e: React.FormEvent) => void;
onSubmit: (e: React.FormEvent) => Promise<void>;
stateHandler: {
inputStates: INewUserData;
inputsSetStates: SetStateInputMethod<keyof INewUserData>;

View File

@ -19,7 +19,7 @@ export default function Sidebar() {
isCurrentPage.pathname === routesData[key].path ? 'bg-primary-300' : ''
}`}
>
<img src={routesData[key].icon} alt='page icon' className='mr-2' />
<img src={routesData[key].icon} alt='page icon' className='mr-2 w-6 h-6' />
<div>{routesData[key].title}</div>
</Link>
);

View File

@ -5,6 +5,7 @@ import CreateUser from '../pages/CreateUser';
import MainPageLayout from '../pages/layouts/MainPageLayout';
import AuthenticationPage from '../pages/Authentication';
import UserLoginLayout from '../pages/layouts/UserLoginLayout';
import CreatePlacePage from '../pages/CreatePlacePage';
export default function Router() {
const location = useLocation();
@ -14,6 +15,7 @@ export default function Router() {
<Route element={<MainPageLayout />}>
<Route index element={<Home />} />
<Route path={routes.createUser} element={<CreateUser />} />
<Route path={routes.createPlace} element={<CreatePlacePage />} />
</Route>
<Route element={<UserLoginLayout />}>
<Route path={routes.authentication} element={<AuthenticationPage />} />

View File

@ -0,0 +1,13 @@
import React from 'react';
import PageTitle from '~/driven/utils/components/page-title/pageTitle';
import { staticMessages } from '~/driven/utils/constants/staticMessages';
import CreatePlace from '~/driving/application/core/places/create-place';
export default function CreatePlacePage() {
return (
<>
<PageTitle className='px-4 py-5' title={staticMessages.global.createPlace} />
<CreatePlace />
</>
);
}

230
yarn.lock
View File

@ -197,7 +197,7 @@
dependencies:
"@babel/types" "^7.18.6"
"@babel/helper-module-imports@^7.21.4":
"@babel/helper-module-imports@^7.16.7", "@babel/helper-module-imports@^7.21.4":
version "7.21.4"
resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz#ac88b2f76093637489e718a90cec6cf8a9b029af"
integrity sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==
@ -1078,6 +1078,13 @@
resolved "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz"
integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==
"@babel/runtime@^7.12.0", "@babel/runtime@^7.18.3", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.7":
version "7.22.3"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.3.tgz#0a7fce51d43adbf0f7b517a71f4c3aaca92ebcbb"
integrity sha512-XsDuspWKLUsxwCp6r7EhsExHtYfbe5oAGQ19kqngTdCPUoPQzOPdUbD/pB9PJiwb2ptYKQDjSJT3R6dC+EPqfQ==
dependencies:
regenerator-runtime "^0.13.11"
"@babel/runtime@^7.12.1", "@babel/runtime@^7.12.5", "@babel/runtime@^7.20.7", "@babel/runtime@^7.8.4", "@babel/runtime@^7.9.2":
version "7.21.0"
resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz"
@ -1149,6 +1156,39 @@
resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz"
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
"@emotion/babel-plugin@^11.11.0":
version "11.11.0"
resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz#c2d872b6a7767a9d176d007f5b31f7d504bb5d6c"
integrity sha512-m4HEDZleaaCH+XgDDsPF15Ht6wTLsgDTeR3WYj9Q/k76JtWhrJjcP4+/XlG8LGT/Rol9qUfOIztXeA84ATpqPQ==
dependencies:
"@babel/helper-module-imports" "^7.16.7"
"@babel/runtime" "^7.18.3"
"@emotion/hash" "^0.9.1"
"@emotion/memoize" "^0.8.1"
"@emotion/serialize" "^1.1.2"
babel-plugin-macros "^3.1.0"
convert-source-map "^1.5.0"
escape-string-regexp "^4.0.0"
find-root "^1.1.0"
source-map "^0.5.7"
stylis "4.2.0"
"@emotion/cache@^11.11.0", "@emotion/cache@^11.4.0":
version "11.11.0"
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.11.0.tgz#809b33ee6b1cb1a625fef7a45bc568ccd9b8f3ff"
integrity sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==
dependencies:
"@emotion/memoize" "^0.8.1"
"@emotion/sheet" "^1.2.2"
"@emotion/utils" "^1.2.1"
"@emotion/weak-memoize" "^0.3.1"
stylis "4.2.0"
"@emotion/hash@^0.9.1":
version "0.9.1"
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.1.tgz#4ffb0055f7ef676ebc3a5a91fb621393294e2f43"
integrity sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==
"@emotion/is-prop-valid@^1.1.0":
version "1.2.0"
resolved "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.0.tgz"
@ -1161,6 +1201,41 @@
resolved "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.0.tgz"
integrity sha512-G/YwXTkv7Den9mXDO7AhLWkE3q+I92B+VqAE+dYG4NGPaHZGvt3G8Q0p9vmE+sq7rTGphUbAvmQ9YpbfMQGGlA==
"@emotion/memoize@^0.8.1":
version "0.8.1"
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.1.tgz#c1ddb040429c6d21d38cc945fe75c818cfb68e17"
integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==
"@emotion/react@^11.8.1":
version "11.11.0"
resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.11.0.tgz#408196b7ef8729d8ad08fc061b03b046d1460e02"
integrity sha512-ZSK3ZJsNkwfjT3JpDAWJZlrGD81Z3ytNDsxw1LKq1o+xkmO5pnWfr6gmCC8gHEFf3nSSX/09YrG67jybNPxSUw==
dependencies:
"@babel/runtime" "^7.18.3"
"@emotion/babel-plugin" "^11.11.0"
"@emotion/cache" "^11.11.0"
"@emotion/serialize" "^1.1.2"
"@emotion/use-insertion-effect-with-fallbacks" "^1.0.1"
"@emotion/utils" "^1.2.1"
"@emotion/weak-memoize" "^0.3.1"
hoist-non-react-statics "^3.3.1"
"@emotion/serialize@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.2.tgz#017a6e4c9b8a803bd576ff3d52a0ea6fa5a62b51"
integrity sha512-zR6a/fkFP4EAcCMQtLOhIgpprZOwNmCldtpaISpvz348+DP4Mz8ZoKaGGCQpbzepNIUWbq4w6hNZkwDyKoS+HA==
dependencies:
"@emotion/hash" "^0.9.1"
"@emotion/memoize" "^0.8.1"
"@emotion/unitless" "^0.8.1"
"@emotion/utils" "^1.2.1"
csstype "^3.0.2"
"@emotion/sheet@^1.2.2":
version "1.2.2"
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.2.tgz#d58e788ee27267a14342303e1abb3d508b6d0fec"
integrity sha512-0QBtGvaqtWi+nx6doRwDdBIzhNdZrXUppvTM4dtZZWEGTXL/XE/yJxLMGlDT1Gt+UHH5IX1n+jkXyytE/av7OA==
"@emotion/stylis@^0.8.4":
version "0.8.5"
resolved "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz"
@ -1171,6 +1246,26 @@
resolved "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz"
integrity sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==
"@emotion/unitless@^0.8.1":
version "0.8.1"
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.1.tgz#182b5a4704ef8ad91bde93f7a860a88fd92c79a3"
integrity sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==
"@emotion/use-insertion-effect-with-fallbacks@^1.0.1":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz#08de79f54eb3406f9daaf77c76e35313da963963"
integrity sha512-jT/qyKZ9rzLErtrjGgdkMBn2OP8wl0G3sQlBb3YPryvKHsjvINUhVaPFfP+fpBcOkmrVOVEEHQFJ7nbj2TH2gw==
"@emotion/utils@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.1.tgz#bbab58465738d31ae4cb3dbb6fc00a5991f755e4"
integrity sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==
"@emotion/weak-memoize@^0.3.1":
version "0.3.1"
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz#d0fce5d07b0620caa282b5131c297bb60f9d87e6"
integrity sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==
"@esbuild/android-arm64@0.16.17":
version "0.16.17"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.16.17.tgz#cf91e86df127aa3d141744edafcba0abdc577d23"
@ -1313,6 +1408,18 @@
resolved "https://registry.npmjs.org/@eslint/js/-/js-8.36.0.tgz"
integrity sha512-lxJ9R5ygVm8ZWgYdUweoq5ownDlJ4upvoWmO4eLxBYHdMo+vZ/Rx0EN6MbKWDJOSUGrqJy2Gt+Dyv/VKml0fjg==
"@floating-ui/core@^1.2.6":
version "1.2.6"
resolved "https://registry.yarnpkg.com/@floating-ui/core/-/core-1.2.6.tgz#d21ace437cc919cdd8f1640302fa8851e65e75c0"
integrity sha512-EvYTiXet5XqweYGClEmpu3BoxmsQ4hkj3QaYA6qEnigCWffTP3vNRwBReTdrwDwo7OoJ3wM8Uoe9Uk4n+d4hfg==
"@floating-ui/dom@^1.0.1":
version "1.2.9"
resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.2.9.tgz#b9ed1c15d30963419a6736f1b7feb350dd49c603"
integrity sha512-sosQxsqgxMNkV3C+3UqTS6LxP7isRLwX8WMepp843Rb3/b0Wz8+MdUkxJksByip3C2WwLugLHN1b4ibn//zKwQ==
dependencies:
"@floating-ui/core" "^1.2.6"
"@humanwhocodes/config-array@^0.11.8":
version "0.11.8"
resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz"
@ -1795,6 +1902,11 @@
resolved "https://registry.npmjs.org/@types/node/-/node-18.15.1.tgz"
integrity sha512-U2TWca8AeHSmbpi314QBESRk7oPjSZjDsR+c+H4ECC1l+kFgpZf8Ydhv3SJpPy51VyZHHqxlb6mTTqYNNRVAIw==
"@types/parse-json@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
"@types/prettier@^2.1.5":
version "2.7.2"
resolved "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz"
@ -1812,6 +1924,20 @@
dependencies:
"@types/react" "*"
"@types/react-select@^5.0.1":
version "5.0.1"
resolved "https://registry.yarnpkg.com/@types/react-select/-/react-select-5.0.1.tgz#04fc85edd34a72675a0ab56ad4c30428aab0e444"
integrity sha512-h5Im0AP0dr4AVeHtrcvQrLV+gmPa7SA0AGdxl2jOhtwiE6KgXBFSogWw8az32/nusE6AQHlCOHQWjP1S/+oMWA==
dependencies:
react-select "*"
"@types/react-transition-group@^4.4.0":
version "4.4.6"
resolved "https://registry.yarnpkg.com/@types/react-transition-group/-/react-transition-group-4.4.6.tgz#18187bcda5281f8e10dfc48f0943e2fdf4f75e2e"
integrity sha512-VnCdSxfcm08KjsJVQcfBmhEQAPnLB8G08hAxn39azX1qYBQ/5RVQuoHuKIcfKOdncuaUvEpFKFzEvbtIMsfVew==
dependencies:
"@types/react" "*"
"@types/react@*", "@types/react@^18.0.27":
version "18.0.28"
resolved "https://registry.npmjs.org/@types/react/-/react-18.0.28.tgz"
@ -2224,6 +2350,15 @@ babel-plugin-jest-hoist@^29.5.0:
"@types/babel__core" "^7.1.14"
"@types/babel__traverse" "^7.0.6"
babel-plugin-macros@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz#9ef6dc74deb934b4db344dc973ee851d148c50c1"
integrity sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==
dependencies:
"@babel/runtime" "^7.12.5"
cosmiconfig "^7.0.0"
resolve "^1.19.0"
babel-plugin-polyfill-corejs2@^0.3.3:
version "0.3.3"
resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz"
@ -2498,7 +2633,7 @@ confusing-browser-globals@^1.0.10:
resolved "https://registry.npmjs.org/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz"
integrity sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==
convert-source-map@^1.6.0, convert-source-map@^1.7.0:
convert-source-map@^1.5.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0:
version "1.9.0"
resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz"
integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==
@ -2515,6 +2650,17 @@ core-js-compat@^3.25.1:
dependencies:
browserslist "^4.21.5"
cosmiconfig@^7.0.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6"
integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==
dependencies:
"@types/parse-json" "^4.0.0"
import-fresh "^3.2.1"
parse-json "^5.0.0"
path-type "^4.0.0"
yaml "^1.10.0"
cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz"
@ -2714,6 +2860,14 @@ dom-accessibility-api@^0.5.6, dom-accessibility-api@^0.5.9:
resolved "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz"
integrity sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==
dom-helpers@^5.0.1:
version "5.2.1"
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902"
integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==
dependencies:
"@babel/runtime" "^7.8.7"
csstype "^3.0.2"
domexception@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz"
@ -3228,6 +3382,11 @@ fill-range@^7.0.1:
dependencies:
to-regex-range "^5.0.1"
find-root@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4"
integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==
find-up@^4.0.0, find-up@^4.1.0:
version "4.1.0"
resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz"
@ -3470,7 +3629,7 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"
hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
hoist-non-react-statics@^3.0.0, hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2:
version "3.3.2"
resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz"
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
@ -4421,6 +4580,11 @@ makeerror@1.0.12:
dependencies:
tmpl "1.0.5"
memoize-one@^6.0.0:
version "6.0.0"
resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045"
integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==
merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz"
@ -4676,7 +4840,7 @@ parent-module@^1.0.0:
dependencies:
callsites "^3.0.0"
parse-json@^5.2.0:
parse-json@^5.0.0, parse-json@^5.2.0:
version "5.2.0"
resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz"
integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
@ -4846,7 +5010,7 @@ prompts@^2.0.1:
kleur "^3.0.3"
sisteransi "^1.0.5"
prop-types@^15.8.1:
prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.8.1:
version "15.8.1"
resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz"
integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
@ -4875,6 +5039,11 @@ pure-rand@^6.0.0:
resolved "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.1.tgz"
integrity sha512-t+x1zEHDjBwkDGY5v5ApnZ/utcd4XYDiJsaQQoptTXgUXX95sDg1elCdJghzicm7n2mbCBJ3uYWr6M22SO19rg==
qrcode.react@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/qrcode.react/-/qrcode.react-3.1.0.tgz#5c91ddc0340f768316fbdb8fff2765134c2aecd8"
integrity sha512-oyF+Urr3oAMUG/OiOuONL3HXM+53wvuH3mtIWQrYmsXoAq0DkvZp2RYUWFSMFtbdOpuS++9v+WAkzNVkMlNW6Q==
querystringify@^2.1.1:
version "2.2.0"
resolved "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz"
@ -4945,6 +5114,31 @@ react-router@6.9.0:
dependencies:
"@remix-run/router" "1.4.0"
react-select@*, react-select@^5.7.3:
version "5.7.3"
resolved "https://registry.yarnpkg.com/react-select/-/react-select-5.7.3.tgz#fa0dc9a23cad6ff3871ad3829f6083a4b54961a2"
integrity sha512-z8i3NCuFFWL3w27xq92rBkVI2onT0jzIIPe480HlBjXJ3b5o6Q+Clp4ydyeKrj9DZZ3lrjawwLC5NGl0FSvUDg==
dependencies:
"@babel/runtime" "^7.12.0"
"@emotion/cache" "^11.4.0"
"@emotion/react" "^11.8.1"
"@floating-ui/dom" "^1.0.1"
"@types/react-transition-group" "^4.4.0"
memoize-one "^6.0.0"
prop-types "^15.6.0"
react-transition-group "^4.3.0"
use-isomorphic-layout-effect "^1.1.2"
react-transition-group@^4.3.0:
version "4.4.5"
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1"
integrity sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==
dependencies:
"@babel/runtime" "^7.5.5"
dom-helpers "^5.0.1"
loose-envify "^1.4.0"
prop-types "^15.6.2"
react@^18.2.0:
version "18.2.0"
resolved "https://registry.npmjs.org/react/-/react-18.2.0.tgz"
@ -5089,6 +5283,15 @@ resolve@^1.1.7, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.22.1:
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
resolve@^1.19.0:
version "1.22.2"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f"
integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==
dependencies:
is-core-module "^2.11.0"
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
resolve@^2.0.0-next.4:
version "2.0.0-next.4"
resolved "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz"
@ -5218,6 +5421,11 @@ source-map-support@0.5.13:
buffer-from "^1.0.0"
source-map "^0.6.0"
source-map@^0.5.7:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==
source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1:
version "0.6.1"
resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
@ -5350,6 +5558,11 @@ styled-components@^5.3.8:
shallowequal "^1.1.0"
supports-color "^5.5.0"
stylis@4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/stylis/-/stylis-4.2.0.tgz#79daee0208964c8fe695a42fcffcac633a211a51"
integrity sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==
supports-color@^5.3.0, supports-color@^5.5.0:
version "5.5.0"
resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz"
@ -5596,6 +5809,11 @@ url-parse@^1.5.3:
querystringify "^2.1.1"
requires-port "^1.0.0"
use-isomorphic-layout-effect@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz#497cefb13d863d687b08477d9e5a164ad8c1a6fb"
integrity sha512-49L8yCO3iGT/ZF9QttjwLF/ZD9Iwto5LnH5LmEdk/6cFmXddqi2ulF0edxTwjj+7mqvpVVGQWvbXZdn32wRSHA==
use-sync-external-store@^1.0.0, use-sync-external-store@^1.2.0:
version "1.2.0"
resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz"
@ -5768,7 +5986,7 @@ yallist@^4.0.0:
resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz"
integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
yaml@^1.10.2:
yaml@^1.10.0, yaml@^1.10.2:
version "1.10.2"
resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz"
integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==