diff --git a/src/driven/adapters/create-place-adapter/createPlaceAdapter.ts b/src/driven/adapters/create-place-adapter/createPlaceAdapter.ts new file mode 100644 index 0000000..401cd35 --- /dev/null +++ b/src/driven/adapters/create-place-adapter/createPlaceAdapter.ts @@ -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(options); + }; + return { + httpHandler, + }; +}; + +export default createPlaceAdapter; diff --git a/src/driven/boundaries/http-boundary/httpBoundary.ts b/src/driven/boundaries/http-boundary/httpBoundary.ts index ae4acc2..435c7d5 100644 --- a/src/driven/boundaries/http-boundary/httpBoundary.ts +++ b/src/driven/boundaries/http-boundary/httpBoundary.ts @@ -46,7 +46,6 @@ export class HTTPPovider { async request(customOptions: HttpOptionsType) { const axiosInstance = this.handleRequestInterceptor(); this.responseIncepter(axiosInstance); - const response = await axiosInstance>(customOptions); if (!response) throw new Error(staticMessages.service.errors[500]); diff --git a/src/driven/utils/configs/appConfig.ts b/src/driven/utils/configs/appConfig.ts index ad7f821..2fc1608 100644 --- a/src/driven/utils/configs/appConfig.ts +++ b/src/driven/utils/configs/appConfig.ts @@ -40,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}`, diff --git a/src/driven/utils/constants/envs.ts b/src/driven/utils/constants/envs.ts index 428a48c..80f6d65 100644 --- a/src/driven/utils/constants/envs.ts +++ b/src/driven/utils/constants/envs.ts @@ -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, }; diff --git a/src/driven/utils/constants/staticMessages.ts b/src/driven/utils/constants/staticMessages.ts index 80fc6cf..d61ef69 100644 --- a/src/driven/utils/constants/staticMessages.ts +++ b/src/driven/utils/constants/staticMessages.ts @@ -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', @@ -26,6 +27,7 @@ export const staticMessages = { success: { createUser: 'user created successfully', createMember: 'member created successfully', + createPlace: 'place created successfully', }, and: 'and', canUseFor: 'can use for', @@ -47,7 +49,7 @@ export const staticMessages = { }, 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!', }, }, diff --git a/src/driving/application/core/places/create-place/infra/CreatePlace.tsx b/src/driving/application/core/places/create-place/infra/CreatePlace.tsx index 46607c4..89d6050 100644 --- a/src/driving/application/core/places/create-place/infra/CreatePlace.tsx +++ b/src/driving/application/core/places/create-place/infra/CreatePlace.tsx @@ -1,15 +1,23 @@ 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 { inputOptions } = createPlaceModel(); - const { formStateData, inputStateHandlers, selectBoxOptions } = useCreatePlaceVm({ + 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 ( { +type ICreatePlaceModel = ICreatePlaceLogicMaker; + +const createPlaceModel = (depenedencies: ICreatePlaceModel): CreatePlaceType => { const { getPlacesTypeOptionsOfSelectBox, getValidParentIdsOptionsOfSelectBox } = getValidOptionsOfSelectBox; + + const { createPlace } = createPlaceLogicMaker(depenedencies); return { + createPlace, inputOptions: { getPlaceType: getPlacesTypeOptionsOfSelectBox, getParentIds: getValidParentIdsOptionsOfSelectBox, diff --git a/src/driving/application/core/places/create-place/model/index.ts b/src/driving/application/core/places/create-place/model/index.ts new file mode 100644 index 0000000..3089503 --- /dev/null +++ b/src/driving/application/core/places/create-place/model/index.ts @@ -0,0 +1,3 @@ +import createPlaceModel from './createPlaceModel'; + +export default createPlaceModel; diff --git a/src/driving/application/core/places/create-place/model/protocols.ts b/src/driving/application/core/places/create-place/model/protocols.ts index 8c54bb5..639bfae 100644 --- a/src/driving/application/core/places/create-place/model/protocols.ts +++ b/src/driving/application/core/places/create-place/model/protocols.ts @@ -1,7 +1,9 @@ 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; inputOptions: { getPlaceType: () => { value: placeTypes; diff --git a/src/driving/application/core/places/create-place/model/submiCreatePlace.ts b/src/driving/application/core/places/create-place/model/submiCreatePlace.ts new file mode 100644 index 0000000..51012a4 --- /dev/null +++ b/src/driving/application/core/places/create-place/model/submiCreatePlace.ts @@ -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; +} + +const createPlaceLogicMaker = (depenedencies: ICreatePlaceLogicMaker) => { + const { httpHandler } = depenedencies; + + const createPlace = async (placeData: createPlaceArguments) => { + return await httpHandler(placeData); + }; + return { + createPlace, + }; +}; + +export default createPlaceLogicMaker; diff --git a/src/driving/application/core/places/create-place/view/CreatePlaceView.tsx b/src/driving/application/core/places/create-place/view/CreatePlaceView.tsx index fdc470b..4774e12 100644 --- a/src/driving/application/core/places/create-place/view/CreatePlaceView.tsx +++ b/src/driving/application/core/places/create-place/view/CreatePlaceView.tsx @@ -3,49 +3,59 @@ import SimpleInput from '~/driven/utils/components/inputs/simple-input/SimpleInp 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 } = props; - const { formState } = formStateData; + const { formStateData, inputStateHandlers, inputOptions, handleSubmitCreatePlaceForm } = props; + const { formState, error, setError } = formStateData; return ( -
- - - -
- null} title={staticMessages.global.submit} /> -
- + <> + {Boolean(error.message) && ( + setError({ message: '', type: 'error' })} + /> + )} +
+ + + +
+ null} title={staticMessages.global.submit} /> +
+ + ); } diff --git a/src/driving/application/core/places/create-place/view/protocol.ts b/src/driving/application/core/places/create-place/view/protocol.ts index 788ce64..ac3b76c 100644 --- a/src/driving/application/core/places/create-place/view/protocol.ts +++ b/src/driving/application/core/places/create-place/view/protocol.ts @@ -19,8 +19,19 @@ export type PlaceFormState = { }; export interface ICreatePlaceProps { + handleSubmitCreatePlaceForm: (e: React.FormEvent) => Promise; formStateData: { formState: PlaceFormState; + error: { + message: string; + type: 'error' | 'success'; + }; + setError: React.Dispatch< + React.SetStateAction<{ + message: string; + type: 'error' | 'success'; + }> + >; setFormState: React.Dispatch>; }; inputStateHandlers: { diff --git a/src/driving/application/core/places/create-place/viewmodel/createPlaceVM.ts b/src/driving/application/core/places/create-place/viewmodel/createPlaceVM.ts index 01e743b..c56f0d1 100644 --- a/src/driving/application/core/places/create-place/viewmodel/createPlaceVM.ts +++ b/src/driving/application/core/places/create-place/viewmodel/createPlaceVM.ts @@ -1,6 +1,9 @@ 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>) => { @@ -25,15 +28,41 @@ const resetParentIdOnChangePlaceType = (setFormState: React.Dispatch { - const { getInputOptions } = dependencies; + const { getInputOptions, createPlaceModel } = dependencies; const { getParentIds, getPlaceType } = getInputOptions; const [formState, setFormState] = useState(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; + console.log(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()(), []); @@ -46,8 +75,11 @@ const useCreatePlaceVm = (dependencies: ICreatePlaceVm) => { }, [formState.placeTypes, places]); return { + handleSubmitCreatePlaceForm, formStateData: { formState, + error, + setError, setFormState, }, inputStateHandlers: { diff --git a/src/driving/application/core/places/create-place/viewmodel/protocols.ts b/src/driving/application/core/places/create-place/viewmodel/protocols.ts index 47c587a..7dd5057 100644 --- a/src/driving/application/core/places/create-place/viewmodel/protocols.ts +++ b/src/driving/application/core/places/create-place/viewmodel/protocols.ts @@ -1,4 +1,5 @@ import { CreatePlaceType } from '../model/protocols'; +import { createPlaceArguments } from '../model/submiCreatePlace'; import { PlaceFormState, placeTypes } from '../view/protocol'; export const initialPlaceFormState: PlaceFormState = { @@ -9,4 +10,5 @@ export const initialPlaceFormState: PlaceFormState = { export interface ICreatePlaceVm { getInputOptions: CreatePlaceType['inputOptions']; + createPlaceModel: (placeData: createPlaceArguments) => Promise; }