еуые
This commit is contained in:
@ -13,6 +13,7 @@ const App = () => {
|
|||||||
const [messageApi, contextHolder] = message.useMessage({
|
const [messageApi, contextHolder] = message.useMessage({
|
||||||
duration: 2,
|
duration: 2,
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<ConfigProvider theme={theme}>
|
<ConfigProvider theme={theme}>
|
||||||
|
|||||||
@ -1,9 +1,14 @@
|
|||||||
import { Form, Input, Menu, MenuProps, Modal, Spin } from "antd";
|
import { Form, Input, Menu, MenuProps, Modal, Spin } from "antd";
|
||||||
import "./styles.css";
|
import "./styles.css";
|
||||||
import { KeyOutlined, UserAddOutlined } from "@ant-design/icons";
|
import { KeyOutlined, UserAddOutlined } from "@ant-design/icons";
|
||||||
import React, { useContext, useState } from "react";
|
import React, { useContext, useEffect, useState } from "react";
|
||||||
import { useLoginMutation, useRegisterMutation } from "../slice/AuthApi";
|
import {
|
||||||
|
useGetUserQuery,
|
||||||
|
useLoginMutation,
|
||||||
|
useRegisterMutation,
|
||||||
|
} from "../slice/AuthApi";
|
||||||
import { MessageContext } from "../App";
|
import { MessageContext } from "../App";
|
||||||
|
import { store, updateToken, updateUser } from "../config/store";
|
||||||
|
|
||||||
const AuthModal = (props: {
|
const AuthModal = (props: {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
@ -15,6 +20,13 @@ const AuthModal = (props: {
|
|||||||
const [current, setCurrent] = useState("login");
|
const [current, setCurrent] = useState("login");
|
||||||
const messageApi = useContext(MessageContext);
|
const messageApi = useContext(MessageContext);
|
||||||
|
|
||||||
|
const { data, isFetching, isError } = useGetUserQuery({});
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isFetching && !isError) {
|
||||||
|
store.dispatch(updateUser(data));
|
||||||
|
}
|
||||||
|
}, [data]);
|
||||||
|
|
||||||
const [loginUser, { isLoading: isLoggingIn }] = useLoginMutation();
|
const [loginUser, { isLoading: isLoggingIn }] = useLoginMutation();
|
||||||
const [registerUser, { isLoading: isRegistering }] = useRegisterMutation();
|
const [registerUser, { isLoading: isRegistering }] = useRegisterMutation();
|
||||||
|
|
||||||
@ -25,6 +37,9 @@ const AuthModal = (props: {
|
|||||||
|
|
||||||
loginUser(formData)
|
loginUser(formData)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
.then((data) => {
|
||||||
|
store.dispatch(updateToken(data.access_token));
|
||||||
|
})
|
||||||
.then(() => props.setOpen(false))
|
.then(() => props.setOpen(false))
|
||||||
.catch(() => messageApi.error("Login failed!"));
|
.catch(() => messageApi.error("Login failed!"));
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,17 +1,23 @@
|
|||||||
import { UserOutlined } from "@ant-design/icons";
|
import { UserOutlined } from "@ant-design/icons";
|
||||||
import { Layout, Menu, MenuProps } from "antd";
|
import { Layout, Menu, MenuProps } from "antd";
|
||||||
import React, { useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import AuthModal from "./AuthModal";
|
import AuthModal from "./AuthModal";
|
||||||
import "./styles.css";
|
import "./styles.css";
|
||||||
|
import { getLocalToken, store, updateUser } from "../config/store";
|
||||||
|
import { useGetUserQuery } from "../slice/AuthApi";
|
||||||
|
|
||||||
const { Header } = Layout;
|
const { Header } = Layout;
|
||||||
|
|
||||||
const HeaderComponent = () => {
|
const HeaderComponent = () => {
|
||||||
const [authModalOpen, setAuthModalOpen] = useState(false);
|
const [authModalOpen, setAuthModalOpen] = useState(false);
|
||||||
|
store.dispatch(getLocalToken());
|
||||||
|
|
||||||
|
const user = store.getState().auth.user;
|
||||||
|
console.log(user);
|
||||||
|
|
||||||
const items: MenuProps["items"] = [
|
const items: MenuProps["items"] = [
|
||||||
{
|
{
|
||||||
label: "Log In",
|
label: user ? user.username : "Log In",
|
||||||
key: "login",
|
key: "login",
|
||||||
icon: <UserOutlined />,
|
icon: <UserOutlined />,
|
||||||
onClick: () => setAuthModalOpen(true),
|
onClick: () => setAuthModalOpen(true),
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
export const baseUrl = "http://localhost/api/"
|
export const baseUrl = "http://localhost/api";
|
||||||
|
|||||||
@ -1,13 +1,35 @@
|
|||||||
import { configureStore, createAction, createReducer } from "@reduxjs/toolkit";
|
import { configureStore, createAction, createReducer } from "@reduxjs/toolkit";
|
||||||
import { setupListeners } from "@reduxjs/toolkit/query";
|
import { setupListeners } from "@reduxjs/toolkit/query";
|
||||||
import { AuthApi } from "../slice/AuthApi";
|
import { AuthApi, User } from "../slice/AuthApi";
|
||||||
|
|
||||||
export type authState = {
|
export type authState = {
|
||||||
token: string | null;
|
token: string | null;
|
||||||
|
user: { name: string | null; username: string } | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
const initialAuthState: authState = {
|
const initialAuthState: authState = {
|
||||||
token: null,
|
token: null,
|
||||||
|
user: null,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const updateToken = createAction<string>("auth/updateToken");
|
||||||
|
export const getLocalToken = createAction("auth/getLocalToken");
|
||||||
|
export const updateUser = createAction<User>("auth/updateUser");
|
||||||
|
|
||||||
|
const parseJwt = (token: string): { sub: string; exp: number } => {
|
||||||
|
const base64Url = token.split(".")[1];
|
||||||
|
const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
|
||||||
|
const jsonPayload = decodeURIComponent(
|
||||||
|
window
|
||||||
|
.atob(base64)
|
||||||
|
.split("")
|
||||||
|
.map(function (c) {
|
||||||
|
return "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2);
|
||||||
|
})
|
||||||
|
.join("")
|
||||||
|
);
|
||||||
|
|
||||||
|
return JSON.parse(jsonPayload);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const store = configureStore({
|
export const store = configureStore({
|
||||||
@ -15,12 +37,19 @@ export const store = configureStore({
|
|||||||
// Add the generated reducer as a specific top-level slice
|
// Add the generated reducer as a specific top-level slice
|
||||||
[AuthApi.reducerPath]: AuthApi.reducer,
|
[AuthApi.reducerPath]: AuthApi.reducer,
|
||||||
auth: createReducer(initialAuthState, (builder) => {
|
auth: createReducer(initialAuthState, (builder) => {
|
||||||
builder.addCase(createAction("auth/token"), (state, _) => {
|
builder.addCase(updateToken, (state, action) => {
|
||||||
|
state.token = action.payload;
|
||||||
|
localStorage.setItem("token", action.payload);
|
||||||
|
});
|
||||||
|
builder.addCase(getLocalToken, (state) => {
|
||||||
const token: string | null = localStorage.getItem("token");
|
const token: string | null = localStorage.getItem("token");
|
||||||
if (token) {
|
if (token) {
|
||||||
state.token = token;
|
state.token = token;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
builder.addCase(updateUser, (state, action) => {
|
||||||
|
state.user = action.payload;
|
||||||
|
});
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
// Adding the api middleware enables caching, invalidation, polling,
|
// Adding the api middleware enables caching, invalidation, polling,
|
||||||
|
|||||||
@ -19,10 +19,15 @@ export interface RegisterRequest {
|
|||||||
password2: string;
|
password2: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TokenResponse = {
|
||||||
|
access_token: string;
|
||||||
|
token_type: string;
|
||||||
|
};
|
||||||
|
|
||||||
export const AuthApi = createApi({
|
export const AuthApi = createApi({
|
||||||
reducerPath: "AuthApi",
|
reducerPath: "AuthApi",
|
||||||
baseQuery: fetchBaseQuery({
|
baseQuery: fetchBaseQuery({
|
||||||
baseUrl: `${baseUrl}auth/`,
|
baseUrl: `${baseUrl}/auth`,
|
||||||
prepareHeaders: (headers, { getState }) => {
|
prepareHeaders: (headers, { getState }) => {
|
||||||
// By default, if we have a token in the store, let's use that for authenticated requests
|
// By default, if we have a token in the store, let's use that for authenticated requests
|
||||||
const token = (getState() as RootState).auth.token;
|
const token = (getState() as RootState).auth.token;
|
||||||
@ -34,11 +39,11 @@ export const AuthApi = createApi({
|
|||||||
}),
|
}),
|
||||||
endpoints: (builder) => ({
|
endpoints: (builder) => ({
|
||||||
getUser: builder.query({
|
getUser: builder.query({
|
||||||
query: () => "me",
|
query: () => "/me",
|
||||||
}),
|
}),
|
||||||
login: builder.mutation({
|
login: builder.mutation({
|
||||||
query: (data: FormData) => ({
|
query: (data: FormData) => ({
|
||||||
url: "token",
|
url: "/token",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: data,
|
body: data,
|
||||||
formData: true,
|
formData: true,
|
||||||
@ -46,7 +51,7 @@ export const AuthApi = createApi({
|
|||||||
}),
|
}),
|
||||||
register: builder.mutation({
|
register: builder.mutation({
|
||||||
query: (data: RegisterRequest) => ({
|
query: (data: RegisterRequest) => ({
|
||||||
url: "register",
|
url: "/register",
|
||||||
method: "POST",
|
method: "POST",
|
||||||
body: data,
|
body: data,
|
||||||
}),
|
}),
|
||||||
|
|||||||
Reference in New Issue
Block a user