Improving user management and auto-refreshing user firms

This commit is contained in:
2025-04-10 01:31:37 +02:00
parent bc059de65b
commit f1fe81a146
13 changed files with 131 additions and 67 deletions

View File

@@ -13,7 +13,7 @@ import routerBindings, {
DocumentTitleHandler,
UnsavedChangesNotifier,
} from "@refinedev/react-router";
import { BrowserRouter, Outlet, Route, Routes } from "react-router";
import { BrowserRouter, Link, Outlet, Route, Routes } from "react-router";
import { authProvider } from "./providers/auth-provider";
import { dataProvider } from "./providers/data-provider";
import { ColorModeContextProvider } from "./contexts/color-mode";
@@ -58,7 +58,7 @@ function App() {
<Route path="/hub" element={ <Hub /> } />
<Route path="/hub/create-firm" element={ <CreateFirm /> } />
</Route>
<Route index element={<h1>HOME</h1>} />
<Route index element={<h1>HOME&nbsp;<Link to={"/login"}>Login</Link></h1>} />
<Route path="/login" element={<Login />} />
<Route path="/register" element={<Register />} />
<Route path="/forgot-password" element={<ForgotPassword />} />

View File

@@ -1,11 +1,7 @@
import {Navigate, useSearchParams} from "react-router";
import {AuthPage} from "@refinedev/mui";
import GoogleIcon from "@mui/icons-material/Google";
import DiscordIcon from "../DiscordIcon";
import { useLogout } from "@refinedev/core";
export const Logout = () => {
const { mutate: logout } = useLogout();
return <button onClick={() => logout()}>Logout</button>;
return <button onClick={() => logout()} >Logout</button>;
};

View File

@@ -10,13 +10,8 @@ import { useGetIdentity } from "@refinedev/core";
import { HamburgerMenu, RefineThemedLayoutV2HeaderProps } from "@refinedev/mui";
import React, { useContext } from "react";
import { ColorModeContext } from "../../contexts/color-mode";
import {Logout} from "../auth/Logout";
type IUser = {
id: number;
email: string;
avatar: string;
};
import { Logout } from "../auth/Logout";
import { IUser } from "../../interfaces";
export const Header: React.FC<RefineThemedLayoutV2HeaderProps> = ({
sticky = true,
@@ -50,7 +45,7 @@ export const Header: React.FC<RefineThemedLayoutV2HeaderProps> = ({
{mode === "dark" ? <LightModeOutlined /> : <DarkModeOutlined />}
</IconButton>
{(user?.avatar || user?.email) && (
{(user?.email) && (
<Stack
direction="row"
gap="16px"
@@ -70,7 +65,7 @@ export const Header: React.FC<RefineThemedLayoutV2HeaderProps> = ({
{user?.email}
</Typography>
)}
<Avatar src={user?.avatar} alt={user?.email} />
<Avatar src={"user?.avatar"} alt={user?.email} />
<Logout />
</Stack>
)}

View File

@@ -0,0 +1,13 @@
export type IFirm = {
instance: string,
name: string
}
type User = {
id: number,
email: string,
firms: [IFirm],
};
export type IUser = User | null;

View File

@@ -8,10 +8,11 @@ import CrudTextWidget from "./widgets/crud-text-widget";
import UnionEnumField from "./fields/union-enum";
type Props = {
schemaName: string,
resource: string,
id?: string,
//onSubmit: (data: IChangeEvent, event: FormEvent<any>) => void
schemaName: string,
resource: string,
id?: string,
//onSubmit: (data: IChangeEvent, event: FormEvent<any>) => void
onSuccess?: (data: any) => void
}
const customWidgets: RegistryWidgetsType = {
@@ -22,12 +23,13 @@ const customFields: RegistryFieldsType = {
AnyOfField: UnionEnumField
}
export const CrudForm: React.FC<Props> = ({schemaName, resource, id}) => {
export const CrudForm: React.FC<Props> = ({ schemaName, resource, id, onSuccess }) => {
const { onFinish, query, formLoading } = useForm({
resource: resource,
action: id === undefined ? "create" : "edit",
redirect: "show",
id,
onMutationSuccess: (data: any) => { if (onSuccess) { onSuccess(data) } },
});
const record = query?.data?.data;

View File

@@ -1,7 +1,19 @@
import { useInvalidateAuthStore } from "@refinedev/core";
import { CrudForm } from "../../lib/crud/components/crud-form";
import {empty_user} from "../../providers/auth-provider";
export const CreateFirm = () => {
const invalidateAuthStore = useInvalidateAuthStore()
const refreshUser = () => {
empty_user();
invalidateAuthStore().then();
}
return (
<CrudForm schemaName={"FirmCreate"} resource={"firms"} />
<CrudForm
schemaName={"FirmCreate"}
resource={"firms"}
onSuccess={() => { refreshUser() }}
/>
)
}

View File

@@ -1,12 +1,38 @@
import { Button } from "@mui/material";
import { Link } from "react-router";
import { useGetIdentity } from "@refinedev/core";
type Firm = {
name: string,
instance: string,
}
type User = {
firms: [Firm],
}
export const Hub = () => {
const user = useGetIdentity<User>();
console.log(user);
let ownFirms = [];
let workFirms = [];
//firms.forEach((f, index) => {
// workFirms.push(<li>{f.instance}/{f.name}</li>)
//})
//{firms.map((f: Firm, index) => (
// <li key={index}>{f.instance} / {f.name}</li>
// ))}
return (
<div>
<h1>HUB</h1>
<p>List of managed firms</p>
<p>List of firm you're working atx</p>
<ul>
<li></li>
</ul>
<p>List of firm you're working at</p>
<ul>
</ul>
<Link to="/hub/create-firm" ><Button >Create a new firm</Button></Link>
</div>
);

View File

@@ -1,4 +1,6 @@
import isEmpty from 'lodash/isEmpty';
import { AuthProvider } from "@refinedev/core";
import {IUser} from "../interfaces";
const API_URL = "/api/v1";
const LOCAL_STORAGE_USER_KEY = "rpk-gui-current-user";
@@ -55,17 +57,24 @@ export const authProvider: AuthProvider = {
return { success: false };
},
check: async () => {
return { authenticated: Boolean(get_user()) };
if (get_user() == null) {
return {
authenticated: false,
redirectTo: "/login",
logout: true
}
}
return { authenticated: true };
},
getIdentity: async () => {
getIdentity: async (): Promise<IUser> => {
const user = get_user();
if (user != null) {
if (user !== null && !isEmpty(user)) {
return user;
}
const response = await fetch(`${API_URL}/users/me`);
if (response.status < 200 || response.status > 299) {
return
return null;
}
const user_data = await response.json();
store_user(user_data)
@@ -163,6 +172,10 @@ function forget_user() {
localStorage.removeItem(LOCAL_STORAGE_USER_KEY);
}
export function empty_user() {
store_user({})
}
function findGetParameter(parameterName: string) {
let result = null, tmp = [];
location.search.substr(1).split("&")