Skip to content

Commit

Permalink
update: level 2.0 codes
Browse files Browse the repository at this point in the history
  • Loading branch information
FahimMontasir committed Jan 24, 2024
1 parent 8bc42fd commit f9dbd72
Show file tree
Hide file tree
Showing 11 changed files with 186 additions and 26 deletions.
24 changes: 6 additions & 18 deletions dashboard/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).

## Getting Started

First, run the development server:
Expand All @@ -14,25 +12,15 @@ pnpm dev

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.

[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.

The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.

This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.

## Learn More

To learn more about Next.js, take a look at the following resources:

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
- [@reduxjs/toolkit](https://redux-toolkit.js.org/) - The official, opinionated, batteries-included toolset for efficient Redux development
- [axios](https://axios-http.com/docs/intro) - Promise based HTTP client for the browser and node.js
- [formik](https://formik.org/) - Build forms in React, without the tears
- [yup](https://www.npmjs.com/package/yup) - Yup is a schema builder for runtime value parsing and validation.
- [tailwindcss](https://tailwindcss.com/) - Rapidly build modern websites without ever leaving your HTML.
- [jwt-decode](jwt-decode)
18 changes: 10 additions & 8 deletions dashboard/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import "@/styles/globals.css";
import { Metadata } from "next";
import Providers from '@/lib/Providers';
import '@/styles/globals.css';
import { Metadata } from 'next';

export const metadata: Metadata = {
title: "ES Dashboard",
description: "English Sphere Dashboard",
authors: [{ name: "Fahim Montasir", url: "https://moontasir.web.app/" }],
keywords:
"ES Dashboard, English Sphere Dashboard, English Sphere content center",
title: 'ES Dashboard',
description: 'English Sphere Dashboard',
authors: [{ name: 'Fahim Montasir', url: 'https://moontasir.web.app/' }],
keywords: 'ES Dashboard, English Sphere Dashboard, English Sphere content center',
};

export default function RootLayout({
Expand All @@ -18,7 +18,9 @@ export default function RootLayout({
}) {
return (
<html lang="en">
<body>{children}</body>
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}
9 changes: 9 additions & 0 deletions dashboard/src/lib/Providers.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use client';
import { store } from '@/redux/store';
import { Provider } from 'react-redux';

const Providers = ({ children }: { children: React.ReactNode }) => {
return <Provider store={store}>{children}</Provider>;
};

export default Providers;
18 changes: 18 additions & 0 deletions dashboard/src/redux/api/authApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { tagTypes } from '../tag-types';
import { baseApi } from './baseApi';
const AUTH_URL = '/auth';

export const authApi = baseApi.injectEndpoints({
endpoints: build => ({
userLogin: build.mutation({
query: loginData => ({
url: `${AUTH_URL}/login`,
method: 'POST',
data: loginData,
}),
invalidatesTags: [tagTypes.user],
}),
}),
});

export const { useUserLoginMutation } = authApi;
12 changes: 12 additions & 0 deletions dashboard/src/redux/api/baseApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { axiosBaseQuery } from '@/helpers/axios/axiosBaseQuery';
import { getBaseUrl } from '@/helpers/config/envConfig';
import { createApi } from '@reduxjs/toolkit/query/react';
import { tagTypesList } from '../tag-types';

// Define a service using a base URL and expected endpoints
export const baseApi = createApi({
reducerPath: 'api',
baseQuery: axiosBaseQuery({ baseUrl: getBaseUrl() }),
endpoints: () => ({}),
tagTypes: tagTypesList,
});
69 changes: 69 additions & 0 deletions dashboard/src/redux/api/courseApi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { ICourse, IMeta } from '@/types';
import { baseApi } from './baseApi';
import { tagTypes } from '../tag-types';

const COURSE_URL = '/courses';

export const courseApi = baseApi.injectEndpoints({
endpoints: build => ({
// get all
courses: build.query({
query: (arg: Record<string, any>) => {
return {
url: COURSE_URL,
method: 'GET',
params: arg,
};
},
transformResponse: (response: ICourse[], meta: IMeta) => {
return {
courses: response,
meta,
};
},
providesTags: [tagTypes.course],
}),
// get single
course: build.query({
query: (id: string) => ({
url: `${COURSE_URL}/${id}`,
method: 'GET',
}),
providesTags: [tagTypes.course],
}),
// create
addCourse: build.mutation({
query: data => ({
url: COURSE_URL,
method: 'POST',
data,
}),
invalidatesTags: [tagTypes.course],
}),
// update
updateCourse: build.mutation({
query: data => ({
url: `${COURSE_URL}/${data.id}`,
method: 'PATCH',
data: data.body,
}),
invalidatesTags: [tagTypes.course],
}),
// delete
deleteCourse: build.mutation({
query: id => ({
url: `${COURSE_URL}/${id}`,
method: 'DELETE',
}),
invalidatesTags: [tagTypes.course],
}),
}),
});

export const {
useCoursesQuery,
useCourseQuery,
useAddCourseMutation,
useDeleteCourseMutation,
useUpdateCourseMutation,
} = courseApi;
28 changes: 28 additions & 0 deletions dashboard/src/redux/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import type { RootState, AppDispatch } from "./store";
import { useEffect, useState } from "react";

// Use throughout your app instead of plain `useDispatch` and `useSelector`
export const useAppDispatch: () => AppDispatch = useDispatch;
export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;

interface IDebounced {
searchQuery: string;
delay: number;
}

export const useDebounced = ({ searchQuery, delay }: IDebounced) => {
const [debouncedValue, setDebouncedValue] = useState<string>(searchQuery);

useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(searchQuery);
}, delay);

return () => {
clearTimeout(handler);
};
}, [searchQuery, delay]);

return debouncedValue;
};
6 changes: 6 additions & 0 deletions dashboard/src/redux/rootReducer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { baseApi } from "./api/baseApi";

export const reducer = {
[baseApi.reducerPath]: baseApi.reducer,
}

16 changes: 16 additions & 0 deletions dashboard/src/redux/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { baseApi } from './api/baseApi';
import { reducer } from './rootReducer';
import { configureStore } from '@reduxjs/toolkit'

export const store = configureStore({
reducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(baseApi.middleware),
})



// Infer the `RootState` and `AppDispatch` types from the store itself
export type RootState = ReturnType<typeof store.getState>
// Inferred type: {posts: PostsState, comments: CommentsState, users: UsersState}
export type AppDispatch = typeof store.dispatch
6 changes: 6 additions & 0 deletions dashboard/src/redux/tag-types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export enum tagTypes {
course = 'course',
user = 'user',
}

export const tagTypesList = [tagTypes.course, tagTypes.user];
6 changes: 6 additions & 0 deletions dashboard/src/schemas/login.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import * as yup from "yup";

export const loginSchema = yup.object().shape({
id: yup.string().required("UserId is required"),
password: yup.string().min(6).max(32).required(),
});

0 comments on commit f9dbd72

Please sign in to comment.