Skip to content

Commit

Permalink
add shadui sonner, add tailwind, add authSlice, add authThunk, update…
Browse files Browse the repository at this point in the history
… userAuthForm
  • Loading branch information
VanyaMate committed Apr 10, 2024
1 parent 1a53c19 commit fd79a9e
Show file tree
Hide file tree
Showing 46 changed files with 922 additions and 256 deletions.
17 changes: 17 additions & 0 deletions components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "src/shared/styles/global-tailwind.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/shared/ui-shad",
"utils": "@/shared/lib"
}
}
1 change: 1 addition & 0 deletions json-server/index.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ server.post('/login', (req, res) => {
);

if (userFromBd) {
delete userFromBd.password;
return res.json(userFromBd);
}

Expand Down
585 changes: 463 additions & 122 deletions package-lock.json

Large diffs are not rendered by default.

16 changes: 13 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"build:view": "npx vite-bundle-visualizer",
"preview": "vite preview",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"lint:fix": "eslint . --fix --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
Expand All @@ -26,17 +27,25 @@
"prepare": "husky install"
},
"dependencies": {
"@radix-ui/react-icons": "^1.3.0",
"@reduxjs/toolkit": "^2.2.3",
"axios": "^1.6.8",
"class-variance-authority": "^0.7.0",
"classnames": "^2.5.1",
"clsx": "^2.1.0",
"i18next": "^23.10.1",
"i18next-browser-languagedetector": "^7.2.0",
"i18next-http-backend": "^2.5.0",
"next-themes": "^0.3.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-i18next": "^14.1.0",
"react-icons": "^5.0.1",
"react-redux": "^9.1.0",
"react-router-dom": "^6.22.3"
"react-router-dom": "^6.22.3",
"sonner": "^1.4.41",
"tailwind-merge": "^2.2.2",
"tailwindcss-animate": "^1.0.7"
},
"devDependencies": {
"@babel/preset-env": "^7.24.3",
Expand Down Expand Up @@ -74,6 +83,7 @@
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.6",
"eslint-plugin-storybook": "^0.8.0",
"husky": "^8.0.0",
"jest": "^29.7.0",
"jest-css-modules": "^2.1.0",
"jest-environment-jsdom": "^29.7.0",
Expand All @@ -85,9 +95,9 @@
"storybook": "^8.0.5",
"stylelint": "^16.3.1",
"stylelint-config-standard-scss": "^13.0.0",
"tailwindcss": "^3.4.3",
"ts-node": "^10.9.2",
"typescript": "^5.2.2",
"vite": "^5.2.0",
"husky": "^8.0.0"
"vite": "^5.2.0"
}
}
7 changes: 2 additions & 5 deletions playwright/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,8 @@ import { BrowserRouter } from 'react-router-dom';
import { I18nextProvider } from 'react-i18next';
import i18n from './i18n/config.ts';
import React from 'react';
import ThemeProvider
from '../src/components/shared/ui/theme/ThemeContext/providers/ThemeProvider';
import ErrorBoundary
from '../src/components/shared/ui/errors/ErrorBoundary/ErrorBoundary';
import { Theme } from '@/components/shared/ui/theme/ThemeContext/types/themes.ts';
import { Theme, ThemeProvider } from '@/app';
import { ErrorBoundary } from '@/shared/ui-kit';


export type HooksConfig = {
Expand Down
4 changes: 3 additions & 1 deletion public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@
"user_auth_form_enter_button": "LogIn",
"user_registration_form_enter_button": "Registration",
"user_auth_form_login_label": "Login",
"user_auth_form_password_label": "Password"
"user_auth_form_password_label": "Password",
"auth_error_title": "Authorisation Error",
"auth_success_title": "Welcome back"
}
4 changes: 3 additions & 1 deletion public/locales/ru/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@
"user_auth_form_enter_button": "Войти",
"user_registration_form_enter_button": "Зарегистрироваться",
"user_auth_form_login_label": "Логин",
"user_auth_form_password_label": "Пароль"
"user_auth_form_password_label": "Пароль",
"auth_error_title": "Ошибка авторизации",
"auth_success_title": "Добро пожаловать"
}
9 changes: 7 additions & 2 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@
- **TypeScript**
- **React**
- **React-Router-Dom**
- **Redux Toolkit**
- **Redux**
- **Redux Toolkit**
- **Redux Thunk**
- **SCSS** + **CSS Modules**
- **I18N-Next**
- **Shadcn UI** - `только sonner`
- **Tailwind**
- **Axios** - `возможно уберу. 25кб слишком много.`

### DevTools

Expand All @@ -32,7 +37,7 @@
- **Jest**
- **React testing library**
- **Storybook**
- **~~Loki~~** - `слишком с ним много проблем`
- **~~Loki~~** - `слишком с ним много проблем (возможно из-за storybook ^8..`
- **~~reg-cli~~** - `не нужен для pw`
- **_Playwright_** - `под вопросом. не работает React.Context`
- **Husky**
Expand Down
4 changes: 3 additions & 1 deletion src/app/i18n/config/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ i18n
interpolation: {
escapeValue: false,
},
});
});

export const i18nConfig = i18n;
3 changes: 2 additions & 1 deletion src/app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ export * from './types';
export * from './i18n';
export * from './redux';
export * from './routes';
export * from './theme';
export * from './theme';
export * from './validation';
4 changes: 3 additions & 1 deletion src/app/redux/config/index.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
import { configureStore } from '@reduxjs/toolkit';
import { userReducer, UserSchema } from '@/app';
import { authReducer, AuthSchema, userReducer, UserSchema } from '@/app';


export interface GlobalStoreSchema {
user: UserSchema;
auth: AuthSchema;
}

export const createGlobalStore = function (initialState?: GlobalStoreSchema) {
return configureStore<GlobalStoreSchema>({
reducer : {
user: userReducer,
auth: authReducer,
},
devTools : __IS_DEV__,
preloadedState: initialState,
Expand Down
3 changes: 2 additions & 1 deletion src/app/redux/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from './config';
export * from './providers';
export * from './slices';
export * from './slices';
export * from './types/thunkDispatch.type.ts';
6 changes: 6 additions & 0 deletions src/app/redux/slices/auth/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export * from './slice/auth.slice.ts';
export * from './types/auth.schema.ts';
export * from './thunks/authByUsername.ts';
export * from './selectors/getAuthPending.ts';
export * from './selectors/getAuthState.ts';
export * from './selectors/getAuthError.ts';
5 changes: 5 additions & 0 deletions src/app/redux/slices/auth/selectors/getAuthError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { createSelector } from '@reduxjs/toolkit';
import { getAuthState } from '@/app/redux/slices/auth/selectors/getAuthState.ts';


export const getAuthError = createSelector(getAuthState, (state) => state.error);
5 changes: 5 additions & 0 deletions src/app/redux/slices/auth/selectors/getAuthPending.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { createSelector } from '@reduxjs/toolkit';
import { getAuthState } from '@/app/redux/slices/auth/selectors/getAuthState.ts';


export const getAuthPending = createSelector(getAuthState, (state) => state.isPending);
4 changes: 4 additions & 0 deletions src/app/redux/slices/auth/selectors/getAuthState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { GlobalStoreSchema } from '@/app';


export const getAuthState = (state: GlobalStoreSchema) => state.auth;
40 changes: 40 additions & 0 deletions src/app/redux/slices/auth/slice/auth.slice.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { createSlice } from '@reduxjs/toolkit';
import { AuthSchema } from '..';
import { authByUsername } from '@/app/redux/slices/auth/thunks/authByUsername.ts';
import { toast } from 'sonner';
import { i18nConfig } from '@/app';


const initialState: AuthSchema = {
isPending: false,
error : null,
};

export const authSlice = createSlice({
name : 'auth',
initialState : initialState,
reducers : {},
extraReducers: (builder) => {
builder.addCase(authByUsername.fulfilled, (state) => {
state.isPending = false;
state.error = null;
toast(i18nConfig.t('auth_success_title'), { duration: 3000 });
});
builder.addCase(authByUsername.pending, (state) => {
state.isPending = true;
state.error = null;
});
builder.addCase(authByUsername.rejected, (state, action) => {
state.isPending = false;
state.error = action.payload ?? {
code : 500,
message: 'Unknown error',
};
toast(i18nConfig.t('auth_error_title'), {
duration: 5000, description: state.error.message,
});
});
},
});

export const { actions: authActions, reducer: authReducer } = authSlice;
Empty file.
40 changes: 40 additions & 0 deletions src/app/redux/slices/auth/thunks/authByUsername.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { createAsyncThunk } from '@reduxjs/toolkit';
import { AuthErrorType, User } from '@/app';
import axios, { AxiosError } from 'axios';


export type AuthByUsernameProps = {
username: string;
password: string;
remember?: boolean;
}

export type AuthThunkApiConfig = {
rejectValue: AuthErrorType | null;
}

export type ServerErrorResponse = {
message: string;
}

export const authByUsername = createAsyncThunk<User, AuthByUsernameProps, AuthThunkApiConfig>(
'auth/byUsername',
async (authData, thunkAPI) => {
try {
return await axios.post('http://localhost:8000/login', authData);
} catch (e: any) {
const error: AxiosError<ServerErrorResponse, any> = e as AxiosError<ServerErrorResponse, any>;
if (error?.response) {
return thunkAPI.rejectWithValue({
code : error.response.status,
message: error.response.data.message,
});
} else {
return thunkAPI.rejectWithValue({
code : 500,
message: e?.message ?? 'Unknown error',
});
}
}
},
);
9 changes: 9 additions & 0 deletions src/app/redux/slices/auth/types/auth.schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export type AuthErrorType = {
code: number;
message: string;
}

export type AuthSchema = {
isPending: boolean;
error: AuthErrorType | null;
}
3 changes: 2 additions & 1 deletion src/app/redux/slices/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './user';
export * from './user';
export * from './auth';
3 changes: 2 additions & 1 deletion src/app/redux/slices/user/slice/user.slice.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { createSlice } from '@reduxjs/toolkit';
import { UserSchema } from '..';


const initialState: Current = {
const initialState: UserSchema = {
authData: null,
};

Expand Down
2 changes: 1 addition & 1 deletion src/app/redux/slices/user/types/user.schema.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { User } from '@/global/types/user';
import { User } from '@/app';


export type UserSchema = {
Expand Down
5 changes: 5 additions & 0 deletions src/app/redux/types/thunkDispatch.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { ThunkDispatch } from '@reduxjs/toolkit';
import { GlobalStoreSchema } from '@/app';


export type ThunkDispatchType = ThunkDispatch<GlobalStoreSchema, any, any>;
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import { expect, test } from '@playwright/experimental-ct-react';
import { HooksConfig } from '$/playwright';
import TestContainer from '@/components/shared/tests/ui/TestContainer.tsx';
import ToggleThemeButton
from '@/components/shared/ui/theme/ThemeContext/ui/ToggleThemeButton/ToggleThemeButton.tsx';
import { Theme } from '@/components/shared/ui/theme/ThemeContext/types/themes.ts';
import { delay } from '@/components/shared/tests/helpers/delay.ts';
import { delay, TestContainer } from '@/shared/tests';
import { Theme, ToggleThemeButton } from '@/app';


test('ToggleThemeButton render and func', async ({ page, mount }) => {
Expand Down
7 changes: 5 additions & 2 deletions src/app/ui/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { FC, memo, StrictMode } from 'react';
import { I18nextProvider } from 'react-i18next';
import {
i18nConfig,
MainSiteRouter,
ReduxGlobalStoreProvider,
ThemeProvider,
} from '@/app';
import { BrowserRouter } from 'react-router-dom';
import { ErrorBoundary, ScreenHeight } from '@/shared/ui-kit';
import { FooterNavBar, HeaderNavBar } from '@/widgets/navigation';
import i18n from 'i18next';
import '@/shared/styles/index.scss';
import { Toaster } from '@/shared/ui-shad';


export type AppProps = {};
Expand All @@ -20,7 +21,7 @@ export const App: FC<AppProps> = memo(function App (props) {
return (
<StrictMode>
<ReduxGlobalStoreProvider>
<I18nextProvider i18n={ i18n }>
<I18nextProvider i18n={ i18nConfig }>
<BrowserRouter>
<ThemeProvider
isPageTheme={ true }
Expand All @@ -36,6 +37,8 @@ export const App: FC<AppProps> = memo(function App (props) {
{/* eslint-disable-next-line react/jsx-max-depth */ }
<MainSiteRouter/>
</ScreenHeight>
{/* eslint-disable-next-line react/jsx-max-depth */ }
<Toaster/>
</ErrorBoundary>
</ThemeProvider>
</BrowserRouter>
Expand Down
3 changes: 3 additions & 0 deletions src/app/validation/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './types/validator.ts';
export * from './user/login.validators.ts';
export * from './user/password.validators.ts';
1 change: 1 addition & 0 deletions src/app/validation/types/validator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export type Validator<Type> = (value: Type) => string;
Loading

0 comments on commit fd79a9e

Please sign in to comment.