auth kinda works now

This commit is contained in:
2024-04-08 15:12:55 +03:00
parent 3594d9deca
commit f032751aa2
5 changed files with 243 additions and 149 deletions

View File

@ -1,18 +1,27 @@
import React from "react"; import React, { createContext } from "react";
import { ConfigProvider } from "antd"; import { ConfigProvider, message } from "antd";
import "./App.css"; import "./App.css";
import HeaderComponent from "./components/HeaderComponent"; import HeaderComponent from "./components/HeaderComponent";
import { theme } from "./config/style"; import { theme } from "./config/style";
import { Provider } from "react-redux"; import { Provider } from "react-redux";
import { store } from "./config/store"; import { store } from "./config/store";
import { MessageInstance } from "antd/es/message/interface";
export const MessageContext = createContext({} as MessageInstance);
const App = () => { const App = () => {
const [messageApi, contextHolder] = message.useMessage({
duration: 2,
});
return ( return (
<Provider store={store}> <Provider store={store}>
<ConfigProvider theme={theme}> <ConfigProvider theme={theme}>
<div className="content"> <MessageContext.Provider value={messageApi}>
<HeaderComponent /> <div className="content">
</div> {contextHolder}
<HeaderComponent />
</div>
</MessageContext.Provider>
</ConfigProvider> </ConfigProvider>
</Provider> </Provider>
); );

View File

@ -1,7 +1,9 @@
import { Form, Input, Menu, MenuProps, Modal } 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, { useState } from "react"; import React, { useContext, useState } from "react";
import { useLoginMutation, useRegisterMutation } from "../slice/AuthApi";
import { MessageContext } from "../App";
const AuthModal = (props: { const AuthModal = (props: {
open: boolean; open: boolean;
@ -11,12 +13,20 @@ const AuthModal = (props: {
const [registerForm] = Form.useForm(); const [registerForm] = Form.useForm();
const [current, setCurrent] = useState("login"); const [current, setCurrent] = useState("login");
const messageApi = useContext(MessageContext);
const submitLoginForm = (formData: { const [loginUser, { isLoading: isLoggingIn }] = useLoginMutation();
username: string; const [registerUser, { isLoading: isRegistering }] = useRegisterMutation();
password: string;
}) => { const submitLoginForm = (data: { username: string; password: string }) => {
console.log(formData); const formData = new FormData();
formData.append("username", data.username);
formData.append("password", data.password);
loginUser(formData)
.unwrap()
.then(() => props.setOpen(false))
.catch(() => messageApi.error("Login failed!"));
}; };
const submitRegisterForm = (formData: { const submitRegisterForm = (formData: {
@ -26,6 +36,10 @@ const AuthModal = (props: {
password2: string; password2: string;
}) => { }) => {
console.log(formData); console.log(formData);
registerUser(formData)
.unwrap()
.then(() => props.setOpen(false))
.catch(() => messageApi.error("Registration failed!"));
}; };
const items: MenuProps["items"] = [ const items: MenuProps["items"] = [
@ -42,113 +56,118 @@ const AuthModal = (props: {
]; ];
return ( return (
<Modal <Spin spinning={isLoggingIn || isRegistering}>
open={props.open} <Modal
onCancel={() => props.setOpen(false)} open={props.open}
onOk={() => { onCancel={() => props.setOpen(false)}
current === "register" && registerForm.submit(); onOk={() => {
current === "login" && loginForm.submit(); current === "register" && registerForm.submit();
}} current === "login" && loginForm.submit();
okText={current === "login" ? "Log In" : "Register"} }}
> okText={current === "login" ? "Log In" : "Register"}
<Menu confirmLoading={isLoggingIn}
onClick={(e) => setCurrent(e.key)} >
mode="horizontal" <Menu
selectedKeys={[current]} onClick={(e) => setCurrent(e.key)}
items={items} mode="horizontal"
/> selectedKeys={[current]}
<br /> items={items}
{current === "register" ? ( />
<Form <br />
form={registerForm} {current === "register" ? (
onFinish={submitRegisterForm} <Form
layout="vertical" form={registerForm}
requiredMark={false} onFinish={submitRegisterForm}
> layout="vertical"
<Form.Item requiredMark={false}
name="username"
label="Username"
rules={[
{
required: true,
message: "Please input your Username!",
},
]}
> >
<Input /> <Form.Item
</Form.Item> name="username"
<Form.Item name="name" label="Display name"> label="Username"
<Input /> rules={[
</Form.Item> {
<Form.Item required: true,
name="password" message: "Please input your Username!",
label="Password"
rules={[
{
required: true,
message: "Please input your password!",
},
]}
>
<Input type="password" />
</Form.Item>
<Form.Item
name="password2"
label="Repeat password"
rules={[
{
required: true,
message: "Please confirm your password!",
},
({ getFieldValue }) => ({
validator(_, value) {
if (!value || getFieldValue("password") === value) {
return Promise.resolve();
}
return Promise.reject(
new Error("The new password that you entered do not match!")
);
}, },
}), ]}
]} >
<Input />
</Form.Item>
<Form.Item name="name" label="Display name">
<Input />
</Form.Item>
<Form.Item
name="password"
label="Password"
rules={[
{
required: true,
message: "Please input your password!",
},
]}
>
<Input type="password" />
</Form.Item>
<Form.Item
name="password2"
label="Repeat password"
rules={[
{
required: true,
message: "Please confirm your password!",
},
({ getFieldValue }) => ({
validator(_, value) {
if (!value || getFieldValue("password") === value) {
return Promise.resolve();
}
return Promise.reject(
new Error(
"The new password that you entered do not match!"
)
);
},
}),
]}
>
<Input type="password" />
</Form.Item>
</Form>
) : (
<Form
form={loginForm}
onFinish={submitLoginForm}
layout="vertical"
requiredMark={false}
> >
<Input type="password" /> <Form.Item
</Form.Item> name="username"
</Form> label="Username"
) : ( rules={[
<Form {
form={loginForm} required: true,
onFinish={submitLoginForm} message: "Please input your Username!",
layout="vertical" },
requiredMark={false} ]}
> >
<Form.Item <Input />
name="username" </Form.Item>
label="Username" <Form.Item
rules={[ name="password"
{ label="Password"
required: true, rules={[
message: "Please input your Username!", {
}, required: true,
]} message: "Please input your Password!",
> },
<Input /> ]}
</Form.Item> >
<Form.Item <Input type="password" />
name="password" </Form.Item>
label="Password" </Form>
rules={[ )}
{ </Modal>
required: true, </Spin>
message: "Please input your Password!",
},
]}
>
<Input type="password" />
</Form.Item>
</Form>
)}
</Modal>
); );
}; };

View File

@ -1,18 +1,37 @@
import { configureStore } 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 } from "../slice/AuthApi";
export type authState = {
token: string | null;
};
const initialAuthState: authState = {
token: null,
};
export const store = configureStore({ export const store = configureStore({
reducer: { reducer: {
// 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) => {
builder.addCase(createAction("auth/token"), (state, _) => {
const token: string | null = localStorage.getItem("token");
if (token) {
state.token = token;
}
});
}),
}, },
// Adding the api middleware enables caching, invalidation, polling, // Adding the api middleware enables caching, invalidation, polling,
// and other useful features of `rtk-query`. // and other useful features of `rtk-query`.
middleware: (getDefaultMiddleware) => middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(AuthApi.middleware), getDefaultMiddleware().concat(AuthApi.middleware),
}) });
// optional, but required for refetchOnFocus/refetchOnReconnect behaviors // optional, but required for refetchOnFocus/refetchOnReconnect behaviors
// see `setupListeners` docs - takes an optional callback as the 2nd arg for customization // see `setupListeners` docs - takes an optional callback as the 2nd arg for customization
setupListeners(store.dispatch) setupListeners(store.dispatch);
export type RootState = ReturnType<typeof store.getState>;
export type AppDispatch = typeof store.dispatch;

View File

@ -1,23 +1,26 @@
export const theme = { export const theme = {
components: { components: {
Modal: { Modal: {
contentBg: "#001529" contentBg: "#001529",
},
Form: {
labelColor: "#77828c"
},
Input: {
activeBg: "#001c36",
},
Button: {
primaryColor: "#001529"
}
}, },
token: { Form: {
colorText: "#ffffff", labelColor: "#77828c",
colorBgContainer: "#001c36", },
colorIcon: "#77828c", Input: {
colorPrimary: "#ffffff", activeBg: "#001c36",
colorPrimaryHover: "#001529", },
} Button: {
}; primaryColor: "#001529",
},
Message: {
contentBg: "#001c36",
},
},
token: {
colorText: "#ffffff",
colorBgContainer: "#001c36",
colorIcon: "#77828c",
colorPrimary: "#ffffff",
colorPrimaryHover: "#001529",
},
};

View File

@ -1,14 +1,58 @@
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react' import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react";
import { baseUrl } from '../config/baseUrl' import { baseUrl } from "../config/baseUrl";
import { RootState } from "../config/store";
export interface User {
username: string;
name: string;
}
export interface UserResponse {
user: User;
token: string;
}
export interface RegisterRequest {
username: string;
name: string | undefined;
password: string;
password2: string;
}
export const AuthApi = createApi({ export const AuthApi = createApi({
reducerPath: 'AuthApi', reducerPath: "AuthApi",
baseQuery: fetchBaseQuery({ baseUrl: `${baseUrl}auth/` }), baseQuery: fetchBaseQuery({
baseUrl: `${baseUrl}auth/`,
prepareHeaders: (headers, { getState }) => {
// By default, if we have a token in the store, let's use that for authenticated requests
const token = (getState() as RootState).auth.token;
if (token) {
headers.set("authorization", `Bearer ${token}`);
}
return headers;
},
}),
endpoints: (builder) => ({ endpoints: (builder) => ({
getUser: builder.query({ getUser: builder.query({
query: () => 'me/', query: () => "me",
}),
login: builder.mutation({
query: (data: FormData) => ({
url: "token",
method: "POST",
body: data,
formData: true,
}),
}),
register: builder.mutation({
query: (data: RegisterRequest) => ({
url: "register",
method: "POST",
body: data,
}),
}), }),
}), }),
}) });
export const { useGetUserQuery } = AuthApi export const { useGetUserQuery, useLoginMutation, useRegisterMutation } =
AuthApi;