From 8b0687d9458807f109acb2193abcd40dd9995f61 Mon Sep 17 00:00:00 2001
From: behnamrhp <behnamrahimpour74@gmail.com>
Date: Mon, 22 May 2023 22:32:14 +0300
Subject: [PATCH] [FEAT]: log out implemented

---
 .env.development                              |  1 +
 .../boundaries/http-boundary/httpBoundary.ts  |  4 +-
 src/driven/utils/configs/appConfig.ts         |  1 +
 src/driven/utils/constants/envs.ts            |  1 +
 src/driven/utils/constants/staticMessages.ts  |  1 +
 .../create-user/viewmodel/CreateUserVM.ts     |  2 -
 .../core/places-list/infra/PlacesList.tsx     | 10 ++-
 .../core/users-list/infra/UsersList.tsx       |  9 ++-
 .../support/sidebar/view/Sidebar.tsx          | 14 ++++-
 src/driving/main/pages/index.tsx              | 62 +++++++++++++++++--
 .../main/pages/layouts/MainPageLayout.tsx     |  3 +-
 .../main/pages/layouts/UserLoginLayout.tsx    |  1 -
 12 files changed, 90 insertions(+), 19 deletions(-)

diff --git a/.env.development b/.env.development
index ff1bac7..233e901 100644
--- a/.env.development
+++ b/.env.development
@@ -3,6 +3,7 @@ VITE_API_AUTH_ORIGIN = https://auth.dev.dipal.ru/api/v1/auth
 VITE_API_AUTH_PHONENUMBER = /start-challenge
 VITE_API_AUTH_LOGIN = /login
 VITE_API_AUTH_REFRESH = /refresh-token
+VITE_API_CREATE_MEMBER = /user_place/members
 VITE_API_PLACES = /place
 VITE_API_USERS = /profile
 VITE_API_USERS_ACCOUNT = /account
diff --git a/src/driven/boundaries/http-boundary/httpBoundary.ts b/src/driven/boundaries/http-boundary/httpBoundary.ts
index 47a236c..3f65647 100644
--- a/src/driven/boundaries/http-boundary/httpBoundary.ts
+++ b/src/driven/boundaries/http-boundary/httpBoundary.ts
@@ -7,8 +7,8 @@ import { apiUrls } from '~/driven/utils/configs/appConfig';
 import { HttpOptionsType } from './protocols';
 
 interface IUserTokens {
-  accessToken: string | null;
-  refreshToken: string | null;
+  accessToken: string | null | undefined;
+  refreshToken: string | null | undefined;
 }
 export class HTTPPovider {
   private userTokens: IUserTokens;
diff --git a/src/driven/utils/configs/appConfig.ts b/src/driven/utils/configs/appConfig.ts
index 2b4d4f8..93bd570 100644
--- a/src/driven/utils/configs/appConfig.ts
+++ b/src/driven/utils/configs/appConfig.ts
@@ -32,6 +32,7 @@ export const apiUrls = {
     getUsers: `${baseApiUrl}${ENVs.apiGetUsers}`,
     createUserAccount: `${baseApiUrl}${ENVs.apiCreateUserAccount}`,
     createUserProfile: `${baseApiUrl}${ENVs.apiCreateUserProfile}`,
+    createMember: `${baseApiUrl}${ENVs.apiCreateMember}`,
   },
   generic: {
     authPhonenumber: `${ENVs.apiAuthOrigin}${ENVs.apiAuthPhonenumber}`,
diff --git a/src/driven/utils/constants/envs.ts b/src/driven/utils/constants/envs.ts
index e347844..102978c 100644
--- a/src/driven/utils/constants/envs.ts
+++ b/src/driven/utils/constants/envs.ts
@@ -8,4 +8,5 @@ export const ENVs = {
   apiGetUsers: process.env.VITE_API_USERS,
   apiCreateUserAccount: process.env.VITE_API_USERS_ACCOUNT,
   apiCreateUserProfile: process.env.VITE_API_USERS_PROFILE,
+  apiCreateMember: process.env.VITE_API_CREATE_MEMBER,
 };
diff --git a/src/driven/utils/constants/staticMessages.ts b/src/driven/utils/constants/staticMessages.ts
index c841036..3acc2a0 100644
--- a/src/driven/utils/constants/staticMessages.ts
+++ b/src/driven/utils/constants/staticMessages.ts
@@ -22,6 +22,7 @@ export const staticMessages = {
     enterOtpCode: 'Enter your Otp Code',
     success: {
       createUser: 'user created successfully',
+      createMember: 'member created successfully',
     },
   },
   service: {
diff --git a/src/driving/application/core/create-user/viewmodel/CreateUserVM.ts b/src/driving/application/core/create-user/viewmodel/CreateUserVM.ts
index 2fd76be..f2e7785 100644
--- a/src/driving/application/core/create-user/viewmodel/CreateUserVM.ts
+++ b/src/driving/application/core/create-user/viewmodel/CreateUserVM.ts
@@ -34,9 +34,7 @@ const useCreateUserVM = (dependencies: IUseCreateUserVm): ICreateUserViewProps =
       await handleSubmitForm(inputsValue);
       setError({ message: staticMessages.global.success.createUser, type: 'success' });
     } catch (errorExc) {
-      console.log('herere', errorExc);
       if (errorExc instanceof AxiosError) {
-        console.log('herere', errorExc);
         setError({ message: errorExc.response?.data?.description, type: 'error' });
       } else if (errorExc instanceof Error) {
         setError({ message: errorExc.message, type: 'error' });
diff --git a/src/driving/application/core/places-list/infra/PlacesList.tsx b/src/driving/application/core/places-list/infra/PlacesList.tsx
index 3b46a98..b3d0422 100644
--- a/src/driving/application/core/places-list/infra/PlacesList.tsx
+++ b/src/driving/application/core/places-list/infra/PlacesList.tsx
@@ -19,12 +19,18 @@ const prepareTheLogicForModel = () => {
   return { getingPlacesLogic, url };
 };
 
-export default function PlacessList() {
+export interface IPlacesListProps {
+  selectedRowId: string;
+  setSelectedRowId: React.Dispatch<React.SetStateAction<string>>;
+}
+
+export default function PlacessList(props: IPlacesListProps) {
+  const { selectedRowId, setSelectedRowId } = props;
   const { getingPlacesLogic, url } = prepareTheLogicForModel();
   const placesModel = async () => await placesListModel(getingPlacesLogic);
 
   const useGetPlacesList = prepareStateManagementForVM<PlacesModel>(url, placesModel);
-  const { selectedRowId, setSelectedRowId, placesData } = usePlacesListVM({
+  const { placesData } = usePlacesListVM({
     useGetPlacesList,
   });
   return <PlacesListView placesList={placesData} selectedRowId={selectedRowId} setSelectedRowId={setSelectedRowId} />;
diff --git a/src/driving/application/core/users-list/infra/UsersList.tsx b/src/driving/application/core/users-list/infra/UsersList.tsx
index 669731f..5b71f59 100644
--- a/src/driving/application/core/users-list/infra/UsersList.tsx
+++ b/src/driving/application/core/users-list/infra/UsersList.tsx
@@ -19,11 +19,16 @@ const usePrepareTheLogicForModel = () => {
   return { getingusersLogic, url };
 };
 
-export default function UsersList() {
+export interface IUsersListProps {
+  selectedRowId: string;
+  setSelectedRowId: React.Dispatch<React.SetStateAction<string>>;
+}
+export default function UsersList(props: IUsersListProps) {
+  const { selectedRowId, setSelectedRowId } = props;
   const { getingusersLogic, url } = usePrepareTheLogicForModel();
   const usersModel = async () => await usersListModel(getingusersLogic);
   const useGetusersList = prepareStateManagementForVM<UsersModel>(url, usersModel);
-  const { selectedRowId, setSelectedRowId, usersData } = useUsersListVM({
+  const { usersData } = useUsersListVM({
     useGetusersList,
   });
   return <UsersListView usersList={usersData} selectedRowId={selectedRowId} setSelectedRowId={setSelectedRowId} />;
diff --git a/src/driving/application/support/sidebar/view/Sidebar.tsx b/src/driving/application/support/sidebar/view/Sidebar.tsx
index 726c54e..f3af15d 100644
--- a/src/driving/application/support/sidebar/view/Sidebar.tsx
+++ b/src/driving/application/support/sidebar/view/Sidebar.tsx
@@ -1,11 +1,14 @@
 import React from 'react';
-import { Link, useLocation } from 'react-router-dom';
+import { Link, useLocation, useNavigate } from 'react-router-dom';
 import { routesData } from '~/driven/utils/configs/appConfig';
 import { icons } from '~/driven/utils/constants/assertUrls';
+import { useUser } from '~/driven/utils/helpers/contexts/userContext';
+import { navigateToAuth } from '~/driven/utils/helpers/globalHelpers';
 
 export default function Sidebar() {
   const isCurrentPage = useLocation();
-
+  const userCTX = useUser();
+  const navigator = useNavigate();
   const pages = Object.keys(routesData).map((routeKey) => {
     const key = routeKey as keyof typeof routesData;
     return (
@@ -27,7 +30,12 @@ export default function Sidebar() {
       <div className='logo'>
         <img src={icons.logo} alt='logo icon' />
       </div>
-      <div className='mt-14 flex flex-col items-baseline'>{pages}</div>
+      <div className='mt-14 flex flex-col items-baseline'>
+        {pages}
+        <div className='mt-auto text-white px-3 absolute bottom-5'>
+          <button onClick={() => navigateToAuth(userCTX, navigator)}>Log out</button>
+        </div>
+      </div>
     </aside>
   );
 }
diff --git a/src/driving/main/pages/index.tsx b/src/driving/main/pages/index.tsx
index a0baa8e..2d51079 100644
--- a/src/driving/main/pages/index.tsx
+++ b/src/driving/main/pages/index.tsx
@@ -1,21 +1,73 @@
-import React from 'react';
+import { AxiosError } from 'axios';
+import React, { useState } from 'react';
+import { HTTPPovider } from '~/driven/boundaries/http-boundary/httpBoundary';
+import { HttpOptionsType } from '~/driven/boundaries/http-boundary/protocols';
+import Notification from '~/driven/utils/components/Notification/Notification';
 import PrimaryButton from '~/driven/utils/components/buttons/primary-button/PrimaryButton';
 import PageTitle from '~/driven/utils/components/page-title/pageTitle';
+import { apiUrls } from '~/driven/utils/configs/appConfig';
 import { staticMessages } from '~/driven/utils/constants/staticMessages';
+import useGetNavigatorAndTokenUpdater from '~/driven/utils/helpers/hooks/getNavigatorAndAccessTokenUpdator';
 import PlacesList from '~/driving/application/core/places-list';
 import UsersList from '~/driving/application/core/users-list';
 
 export default function index() {
+  const [selectedUserRowId, setSelectedUserRowId] = useState<string>('');
+  const [selectedPlaceRowId, setSelectedPlaceRowId] = useState<string>('');
+  const { accessTokenUpdateHandler, notLoginAuth, userData } = useGetNavigatorAndTokenUpdater();
+  const [error, setError] = useState<{ message: string; type: 'error' | 'success' }>({ message: '', type: 'error' });
+
+  const onSubmitMember = async (e: React.FormEvent) => {
+    e.preventDefault();
+    try {
+      const url = apiUrls.core.createMember;
+      const data = {
+        place_id: selectedPlaceRowId,
+        account_id: selectedUserRowId,
+      };
+
+      const options: HttpOptionsType = {
+        url,
+        data,
+        headers: {
+          'Content-Type': 'application/json',
+        },
+        method: 'POST',
+      };
+
+      const userTokens = {
+        accessToken: userData.user?.adminUserData.accessToken || null,
+        refreshToken: userData.user?.adminUserData.refreshToken || null,
+      };
+      const httpProvider = new HTTPPovider(userTokens, accessTokenUpdateHandler, notLoginAuth);
+
+      await httpProvider.request(options);
+      setError({ message: staticMessages.global.success.createMember, 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' });
+      }
+    }
+  };
   return (
     <>
+      {Boolean(error.message) && (
+        <Notification
+          message={error.message}
+          type={error.type}
+          onCloseCallback={() => setError({ message: '', type: 'error' })}
+        />
+      )}
       <PageTitle className='px-4 py-5' title={staticMessages.global.users} />
       <div className='container mx-auto px-4'>
-        <div className='w-full flex flex-row-reverse items-center py-2 sticky top-0'>
+        <form onSubmit={onSubmitMember} className='w-full flex flex-row-reverse items-center py-2 sticky top-0'>
           <PrimaryButton className='text-sm' title={staticMessages.global.submit} onClick={() => null} />
-        </div>
+        </form>
         <div className='md:grid-cols-2 gap-x-4 grid grid-cols-1 mx-auto'>
-          <UsersList />
-          <PlacesList />
+          <UsersList selectedRowId={selectedUserRowId} setSelectedRowId={setSelectedUserRowId} />
+          <PlacesList selectedRowId={selectedPlaceRowId} setSelectedRowId={setSelectedPlaceRowId} />
         </div>
       </div>
     </>
diff --git a/src/driving/main/pages/layouts/MainPageLayout.tsx b/src/driving/main/pages/layouts/MainPageLayout.tsx
index bc004c9..9447647 100644
--- a/src/driving/main/pages/layouts/MainPageLayout.tsx
+++ b/src/driving/main/pages/layouts/MainPageLayout.tsx
@@ -11,7 +11,6 @@ import Sidebar from '~/driving/application/support/sidebar';
  */
 export default function MainPageLayout() {
   const { user, setUser } = useUser();
-  console.log('hi');
   useEffect(() => {
     const storage = StorageService.localStorage<AdminUserModel>();
     const currentUser = storage.getData(appConfig.adminUserStorageKey);
@@ -22,7 +21,7 @@ export default function MainPageLayout() {
   return (
     <div className='flex flex-nowrap min-h-screen'>
       <Sidebar />
-      <main className='dipal-panel w-full text-black bg-white h-fit'>
+      <main className='dipal-panel w-full text-black bg-white h-screen overflow-auto'>
         <Outlet />
       </main>
     </div>
diff --git a/src/driving/main/pages/layouts/UserLoginLayout.tsx b/src/driving/main/pages/layouts/UserLoginLayout.tsx
index 33683f2..dfeee28 100644
--- a/src/driving/main/pages/layouts/UserLoginLayout.tsx
+++ b/src/driving/main/pages/layouts/UserLoginLayout.tsx
@@ -5,7 +5,6 @@ import { useUser } from '~/driven/utils/helpers/contexts/userContext';
 
 export default function UserLoginLayout() {
   const { user } = useUser();
-  console.log('hhhh');
   if (user && user.adminUserData.accessToken) return <Navigate to={routes.usersList} replace />;
   return <Outlet />;
 }