Skip to content

ApertechProjects/SolaSoft

Repository files navigation

Login token,userIdentifier localStorage key null

npm install xlsx import * as xlsx from 'xlsx';

Create App

npx create-react-app 'name'

MUI Install

npm install @mui/material @emotion/react @emotion/styled npm install @fontsource/roboto npm install @mui/icons-material npm install @mui/x-data-grid npm install @mui/x-data-grid-generator npm install @mui/x-date-pickers npm install dayjs --save npm install @mui/lab @mui/material

  • index.html
```

React Toastify

import 'react-toastify/dist/ReactToastify.css';

npm install --save react-toastify

React Router Dom Install

npm install react-router-dom

Redux Install

npm install react-redux npm install @reduxjs/toolkit

Redux Persist

npm install redux-persist

Axios Install

npm install axios

Json Server Install

npm install json-server

1.Pages Structure

  1. İlk olaraq src folder-ində 'pages' folderi yaradırıq.
  2. 'pages' daxilində yaradacağımız səhifələrin folder-lərini və həmin səhifələrin componenti olacaqsa onlarında daxilində 'component' folderi yaradırıq.
  3. Ortaq layout üçün də 'Layout' folderi yaradırıq.
  4. 'Layout' daxilində 'SharedLayout.js' faylı yaradırıq və daxilində səhfələri çağırmaq üçün '' componentini çağırırıq.
  • SharedLayout.js
import { Outlet } from 'react-router-dom'

const SharedLayout = () => {
  return (
    <div>
      <Outlet/>
    </div>
  )
}

export default SharedLayout
  1. Və ən sonunda App.js faylında pages struktunu qoşuruq.
  • App.js
<BrowserRouter>
    <Routes>
      <Route path='/' element={<SharedLayout />}>
        <Route index element={<User />} />
        <Route path='groups' element={<Group />} />
        <Route path='vendors' element={<Vendor />} />
        <Route path='requests' element={<Request />} />
        <Route path='payments' element={<Payment />} />
      </Route>

      <Route path='login' element={<Login />} />
      <Route path='register' element={<Register />} />
      <Route path='*' element={<ErrorPage />} />
  </Routes>
</BrowserRouter>

2.Redux Store

  1. src folderində store folderi və daxilində index.js faylı yaradırıq. "reduxjs/toolkit" kitabxanasından istifadə edərək "store" yaradırıq və "setupListeners" funksiyasından istifadə edərək dinləyicilərə "store.dispatch" funksiyası təyin edilir. 'store' proqramdakı dataların saxlandığı yerdir və dataların yenilənməsi üçün dispatch funksiyasından istifadə olunur.
  • store/index.js
import { configureStore } from "@reduxjs/toolkit";
import { setupListeners } from '@reduxjs/toolkit/dist/query'

export const store = configureStore({
    reducer: {},
})

setupListeners(store.dispatch);
  1. index.js faylında "react-dom/client" kitabxanasındakı "createRoot" funksiyasından istifadə edərək HTML sənədində "root" ID-si olan elementə React tətbiqini təqdim edir. O, həmçinin "react-redux" kitabxanasındakı "Provider" komponentindən istifadə etməklə store tətbiqinin bütün komponentlərinə girişi təmin edilir. "store" və "App" komponentlərindən istifadə edərək tətbiqin başlanğıc nöqtəsini yaradılır.
  • index.js
import { createRoot } from 'react-dom/client';
import { Provider } from 'react-redux';
import { store } from './store'
import App from './App';

const el = document.getElementById('root');
const root = createRoot(el);

root.render(
  <Provider store={store}>
    <App />
  </Provider>
);

3.Redux Authentication

  1. Əvvəlcə proyektdə api-lər token ilə olduğu üçün authentication olunmalıdır. Bunun üçün login sistemi qurmalıyıq. store folderində slice folderi və daxilində 'authSlie' faylı yaradırıq. "@reduxjs/toolkit" kitabxanasından "createSlice" funksiyasından istifadə edərək "auth" slice yaradılır. Bu slice-ın ilkin vəziyyəti token və userIdentifier dəyişənlərinin sıfır olduğu obyektdir. Bu dilimdə iki reducer müəyyən edilmişdir. Birincisi, "setCredentials", action payload dataları götürür və state-dəki token və userIdentifier dəyərlərini yeniləyir. O, həmçinin bu dəyərləri localStorage-də saxlayır. İkinci reducer "logOut" vəziyyətində token və userIdentifier dəyərlərini sıfırlayır, həmçinin localStorage-də token və userIdentifier dəyərlərini silir. Ən sonda, "setCredentials", "logOut" və "authReducer" export edilir.
  • authSlice.js
import { createSlice } from "@reduxjs/toolkit";

const authSlice = createSlice({
    name: 'auth',
    initialState: {
        token: null,
        userIdentifier: null
    },
    reducers: {
        setCredentials: (state, action) => {
            const { data } = action.payload
            state.token = data.token.accessToken
            state.userIdentifier = data.userIdentifier

            localStorage.setItem('token', state.token)
            localStorage.setItem('userIdentifier', state.userIdentifier)
        },
        logOut: (state, action) => {
            state.token = null
            state.userIdentifier = null

            localStorage.removeItem('token')
            localStorage.removeItem('userIdentifier')
        }
    }
})

export const { setCredentials, logOut } = authSlice.actions
export const authReducer = authSlice.reducer
// export const selectCurrentToken = (state) => state.auth.token
  1. Təkrarlanacaq kodlar üçüm src folderində 'config.js' faylı yaradırıq. "baseUrl" dəyişəni "prepareHeaders" funksiyasını təyin edilir. Bu funksiya localStorage-dən "token" və "userIdentifier" dəyərlərini götürür və "token" dəyəri varsa, dəyərləri "authorization" və "authToken" key-ləri ilə birlikdə headers obyektinə əlavə edir. Ən sonda, headers obyektini qaytarır.
  • config.js
export const baseUrl = "http://localhost:7252/api/";

export const prepareHeaders = (headers) => {
    const token = localStorage.getItem("token");
    const userIdentifier = localStorage.getItem("userIdentifier");

    if (token) {
        headers.set('authorization', `Bearer ${token}`);
        headers.set('authToken', `${userIdentifier}`);
    }
    return headers;
}
  1. Hər api-də təkrarlanacaq kod bloku üçün bir helper folderi yaradırıq. Həmin təkrarlanacaq kod bloku baseQuery olduğundan 'createBaseQuery' faylı yaradırıq. "@reduxjs/toolkit/dist/query/react" kitabxanasından "fetchBaseQuery" funksiyasını və "config" faylından "baseUrl" və "prepareHeaders" funksiyaları import edilir. Sonra "createBaseQuery" funksiyasını təyin edirik. Bu funksiya "baseUrl" və "prepareHeaders" funksiyalarından istifadə edərək "fetchBaseQuery" funksiyasını çağırır və qaytarır. Bu, sorğuların ediləcəyi URL və başlıqlar üçün əsas sorğu yaradılır.
  • createBaseQuery
import { fetchBaseQuery } from "@reduxjs/toolkit/dist/query/react";
import { baseUrl, prepareHeaders } from "../../config";

export const createBaseQuery = () => {
    return fetchBaseQuery({
        baseUrl,
        prepareHeaders
    })
}
  1. slice folderində 'tokenSlice.js' faylı yaradırıq.Bu fayl token idarəetmə modulu yaratmaq üçün istifadə olunur. Birincisi, "baseUrl" və "prepareHeaders" kimi konfiqurasiya dəyişənləri üçün "config.js" faylından daxil edir. Sonra o, "fetchBaseQuery" funksiyasından istifadə edərək "baseQuery" yaradır və həmin "baseQuery" üzərində işləyən "createApi" funksiyası ilə API yaradır. Bu API 403 status kodu qəbul edərsə, o, yeni giriş nişanı əldə etmək üçün yeniləmə nişanı göndərir və sonra yeni giriş nişanı ilə orijinal sorğunu yenidən sınayır. Yeniləmə nişanı da etibarsızdırsa, istifadəçi sistemdən çıxır.
  • token.js
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/dist/query/react";
import { logOut, setCredentials } from "./authSlice";
import { baseUrl, prepareHeaders } from "../../config";

const baseQuery = fetchBaseQuery({
    baseUrl,
    prepareHeaders
})

const baseQueryWithReauth = async (args, api, extraOptions) => {
    let result = await baseQuery(args, api, extraOptions);

    if (result?.error?.originalStatus === 403) {
        // send refresh token to get new access token
        const refreshResult = await baseQuery('/refresh', api, extraOptions);
        if (refreshResult?.data) {
            const user = result.data?.data.token.accessToken
            localStorage.setItem('token', result.data?.data.token.accessToken)
            // store the new token
            api.dispatch(setCredentials({ ...refreshResult.data, user }))
            // retry the original query with new access token
            result = await baseQuery(args, api, extraOptions)
        } else {
            api.dispatch(logOut())
        }
    }

    return result
}

export const tokenSlice = createApi({
    baseQuery: baseQueryWithReauth,
    endpoints: builder => ({})
})
  1. api folderində 'authApi.js' faylı yaradırıq. "authApi" yaratmaq üçün "tokenSlice"-dən bir neçə 'endpoints'-i əhatə edir. Xüsusilə, "login" endpoints istifadəçinin daxil olmasını təmin etmək üçün yaradılır. Bu son endpoints istifadəçinin etimadnamələrini (məsələn, istifadəçi adı və parol) göndərməklə POST sorğu edir və onun cavabını alır. Bu endpoints-i istifadə etmək üçün "useLoginMutation" funksiyası export edilir və istifadə olunur.
  • authApi.js
import { tokenSlice } from "../slice/tokenSlice";

const authApi = tokenSlice.injectEndpoints({
    endpoints: builder => ({
        login: builder.mutation({
            query: credentials => ({
                url: 'Account/Login',
                method: 'POST',
                body: { ...credentials }
            })
        }),
    })
})

export const { useLoginMutation } = authApi

export { authApi }
  1. store/index.js -də "reducer" sahəsində "auth" və "tokenSlice" adlı iki fərqli reducer müəyyən edilir. Bu reducerlər tətbiqdə state idarəetməsini təmin edir. Middleware sahəsində redux-toolkit-dən "getDefaultMiddleware" funksiyası çağırılır və tokenSlice.middleware əlavə edilir. "DevTools" sahəsi "doğru" olaraq təyin edilmişdir, belə ki, tətbiqin inkişafı zamanı brauzer vasitəsilə 'store'-nin vəziyyətini izləyə bilərik. "setupListeners" funksiyası "store.dispatch" ilə də çağırılır. Nəhayət, "useLoginMutation" üçün "authApi" faylından import edilir. Bu giriş əməliyyatını yerinə yetirmək üçün istifadə edilən funksiyadır.
  • store/index.js
import { configureStore } from "@reduxjs/toolkit";
import { setupListeners } from '@reduxjs/toolkit/dist/query'
import { authReducer } from "./slice/authSlice";
import { tokenSlice } from "./slice/tokenSlice";

export const store = configureStore({
    reducer: {
        auth: authReducer,
        [tokenSlice.reducerPath]: tokenSlice.reducer,
    },
    middleware: (getDefaultMiddleware) => {
        return getDefaultMiddleware()
            .concat(tokenSlice.middleware);
    },
    devTools: true
})

setupListeners(store.dispatch);

export { useLoginMutation } from './api/authApi'
  1. Login olmadan digər səhifələrə keçmesini blok etmək üçün Layout folderində 'RequireAuth.js' faylı yaradırıq.

Komponent istifadəçinin 'token' adlı dəyişəndən istifadə edərək daxil olub-olmadığını yoxlayır. İstifadəçi daxil olubsa, məzmun Outlet komponenti ilə göstərilir. İstifadəçi daxil deyilsə, Navigate komponenti ilə istifadəçinin giriş səhifəsinə yönləndirilir. 'from' adlı dəyişən ilə istifadəçinin hansı səhifədən gəldiyi məlumat da yönləndirmə prosesi zamanı vəziyyət kimi göndərilir. Bu yolla istifadəçi daxil olduqdan sonra yenidən birinci səhifəyə yönləndirilə bilər. Sonra isə hansı səhifələrin bloklanacağını təyin etmək üçün App.js -də quraşdırırq.

  • RequireAuth.js
import React from 'react'
import { Navigate, Outlet, useLocation } from 'react-router-dom';

const RequireAuth = () => {
    const token = localStorage.getItem('token');
    const location = useLocation();

    return (
        token ? <Outlet /> : <Navigate to='/login' state={{ from: location }} replace />
    )
}

export default RequireAuth
  • App.js
<BrowserRouter>
  <Routes>
    <Route path='/' element={<RequireAuth />}>
      <Route element={<SharedLayout setMode={setMode} mode={mode} setDevMode={setDevMode} devMode={devMode} />}>
        <Route index element={<Test1 />} />
        <Route path='users' element={<User />} />
        <Route path='groups' element={<Group />} />
        <Route path='vendors' element={<Vendor />} />
        <Route path='requests' element={<Request />} />
        <Route path='payments' element={<Payment />} />
        <Route path='settings' element={<Setting />} />
        <Route path='approvalstage' element={<ApprovalStage />} />
        <Route path='test2' element={<Test2 />} />
        <Route path='profile' element={<Profile />} />
      </Route>
    </Route>
    <Route path='login' element={<Login />} />
    <Route path='register' element={<Register />} />
    <Route path='*' element={<ErrorPage />} />
  </Routes>
</BrowserRouter>
  1. Lazım olan hər şey əldə olunduqdan sonra Login componentini yaza bilərik. (/Authentication/Login.js)

4.Redux Toolkit Query

  1. API-ləri rahat çəkə bilərik. Redux Toolkit-in "query" kitabxanasından istifadə edərək API yaradılır. Əvvəlcə createApi funksiyası ilə API obyekti yaradılır. Bu obyektin daxilində bir neçə parametr daxil edilib: reducerPath: Bu API-nin istifadə etdiyi reducer-in yolunu müəyyən edir. baseQuery: API çağırmaq üçün istifadə ediləcək əsas sorğu obyektini təyin edir. Bu sorğu obyekti adətən hər bir API çağırışı üçün istifadə ediləcək ümumi parametrləri əhatə edə bilər. endpoints: Bu API-nin xidmət edə biləcəyi sorğuları və ya əməliyyatları müəyyən edir. Burada yalnız bir sorğu müəyyən edilir: getMenu. Bu sorğu Menu/GetUserMenusWithChilds-ə GET sorğusu verir. Nəhayət, useGetMenuQuery hook-u və menuApi obyekti menuApi obyektindən çıxır. Bu hook komponentlərdə getMenu sorğusundan istifadə etmək üçün istifadə edilə bilər.
  • menuApi.js
import { createApi } from "@reduxjs/toolkit/dist/query/react";
import { createBaseQuery } from "../helper/createBaseQuery";

const menuApi = createApi({
    reducerPath: 'menu',
    baseQuery: createBaseQuery(),
    endpoints(builder) {
        return {
            getMenu: builder.query({
                query: () => {
                    return {
                        url: 'Menu/GetUserMenusWithChilds',
                        method: 'GET'
                    }
                }
            })
        }
    }
})

export const { useGetMenuQuery } = menuApi;
export { menuApi };
  1. store/index.js -dən işə salınır.
  • index.js
import { configureStore } from "@reduxjs/toolkit";
import { setupListeners } from '@reduxjs/toolkit/dist/query'
import { menuApi } from "./api/menuApi";
import { authReducer } from "./slice/authSlice";
import { tokenSlice } from "./slice/tokenSlice";

export const store = configureStore({
    reducer: {
        menu: menuApi.reducer,
        auth: authReducer,
        [tokenSlice.reducerPath]: tokenSlice.reducer,
    },
    middleware: (getDefaultMiddleware) => {
        return getDefaultMiddleware()
            .concat(menuApi.middleware)
            .concat(tokenSlice.middleware);
    },
    devTools: true
})

setupListeners(store.dispatch);

export { useGetMenuQuery } from './api/menuApi';
export { useLoginMutation } from './api/authApi'
  1. Artıq Componentdə həmin dataları çağırıb istifadə edə bilərik.
const { data, isLoading, error } = useGetMenuQuery()

Redux Action

  1. store/action/refresh.js
import { createAction } from '@reduxjs/toolkit';

export const refresh = createAction("REFRESH");
  1. slice
import { createSlice } from "@reduxjs/toolkit";
import { refresh } from "../action/refresh";

const refreshSlice = createSlice({
    name: "refresh",
    initialState:  {},
    reducers: {},
    extraReducers: {
        [refresh]: () => {
          alert("HELLO");
        }
      }
})


export const refreshReducer = refreshSlice.reducer

<Box sx={{ display: 'flex', flexWrap: 'wrap' }}> <Box sx={{ p: 1, m: 1, }}> div 1 <Box sx={{ p: 1, m: 1, }}> div 2

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 6