added settings page
This commit is contained in:
@@ -3,8 +3,9 @@ import { Button, Typography } from "@mui/joy";
|
||||
import InventoryIcon from "@mui/icons-material/Inventory";
|
||||
import AddBoxIcon from "@mui/icons-material/AddBox";
|
||||
import StorageIcon from "@mui/icons-material/Storage";
|
||||
import AccountBoxIcon from "@mui/icons-material/AccountBox";
|
||||
import SettingsIcon from "@mui/icons-material/Settings";
|
||||
import { useNavigate, useMatchRoute } from "@tanstack/react-router";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
export const Sidebar = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -30,7 +31,7 @@ export const Sidebar = () => {
|
||||
level="body-lg"
|
||||
className="text-sm font-medium text-slate-500"
|
||||
>
|
||||
{t("app-subtitle")}
|
||||
{Cookies.get("app-name") ? Cookies.get("app-name") : ""}
|
||||
</Typography>
|
||||
</div>
|
||||
|
||||
@@ -60,12 +61,12 @@ export const Sidebar = () => {
|
||||
{t("storages")}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => navigate({ to: "/app/profile" })}
|
||||
variant={variant("/app/profile")}
|
||||
startDecorator={<AccountBoxIcon />}
|
||||
onClick={() => navigate({ to: "/app/app-settings" })}
|
||||
variant={variant("/app/app-settings")}
|
||||
startDecorator={<SettingsIcon />}
|
||||
className={btnClass}
|
||||
>
|
||||
{t("profile")}
|
||||
{t("settings")}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -40,3 +40,8 @@ export interface AlertInterface {
|
||||
header: string;
|
||||
text: string;
|
||||
}
|
||||
|
||||
export interface SettingsIntf {
|
||||
["app-name"]: string;
|
||||
currency: string;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import { useState } from "react";
|
||||
import { useForm } from "@tanstack/react-form";
|
||||
import { createProduct, getStorages } from "../utils/uxFncs";
|
||||
import type { ProductFormValues } from "../misc/interfaces";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
export const AddProduct = () => {
|
||||
const { t } = useTranslation();
|
||||
@@ -205,7 +206,7 @@ export const AddProduct = () => {
|
||||
)}
|
||||
</form.Field>
|
||||
<Typography level="body-sm" className="text-slate-500">
|
||||
{t("currency")}
|
||||
{Cookies.get("currency")}
|
||||
</Typography>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
|
||||
@@ -29,6 +29,7 @@ import { useQuery } from "@tanstack/react-query";
|
||||
import { getProducts } from "../utils/uxFncs";
|
||||
import { visuallyHidden } from "@mui/utils";
|
||||
import { formatDate } from "../utils/uxFncs";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
type Order = "asc" | "desc";
|
||||
|
||||
@@ -427,7 +428,7 @@ export const InventoryPage = () => {
|
||||
<td className="px-6 py-5">
|
||||
<Typography level="title-md">{row.price}</Typography>
|
||||
<Typography level="body-sm" className="text-slate-400">
|
||||
{t("currency")}
|
||||
{Cookies.get("currency")}
|
||||
</Typography>
|
||||
</td>
|
||||
<td className="px-6 py-5">
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
import { Input, Button, CircularProgress } from "@mui/joy";
|
||||
import { useForm } from "@tanstack/react-form";
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import Cookies from "js-cookie";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import type { SettingsIntf } from "../misc/interfaces";
|
||||
import { mutateSettings, fetchSettings } from "../utils/uxFncs";
|
||||
import { useEffect } from "react";
|
||||
|
||||
export const Settings = () => {
|
||||
const { t } = useTranslation();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const {
|
||||
data: settings,
|
||||
isPending: settingsPending,
|
||||
isSuccess: settingsSuccess,
|
||||
} = useQuery({
|
||||
queryKey: ["settings"],
|
||||
queryFn: fetchSettings,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
Cookies.set("app-name", settings?.data[0].value);
|
||||
Cookies.set("currency", settings?.data[1].value);
|
||||
}, [settingsSuccess]);
|
||||
|
||||
const form = useForm({
|
||||
defaultValues: {
|
||||
"app-name": settings?.data[0].value ?? "",
|
||||
currency: settings?.data[1].value ?? "",
|
||||
},
|
||||
onSubmit: async ({ value }) => {
|
||||
mutate(value);
|
||||
},
|
||||
});
|
||||
|
||||
const { mutate } = useMutation({
|
||||
mutationFn: (values: SettingsIntf) => mutateSettings(values),
|
||||
onSuccess() {
|
||||
queryClient.invalidateQueries({ queryKey: ["settings"] });
|
||||
},
|
||||
});
|
||||
|
||||
return (
|
||||
<>
|
||||
{settingsPending ? (
|
||||
<CircularProgress />
|
||||
) : (
|
||||
<form
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
form.handleSubmit();
|
||||
}}
|
||||
>
|
||||
<form.Field name="app-name">
|
||||
{(field) => (
|
||||
<Input
|
||||
value={field.state.value}
|
||||
onChange={(e) => field.handleChange(e.target.value)}
|
||||
/>
|
||||
)}
|
||||
</form.Field>
|
||||
<form.Field name="currency">
|
||||
{(field) => (
|
||||
<Input
|
||||
value={field.state.value}
|
||||
onChange={(e) => field.handleChange(e.target.value)}
|
||||
/>
|
||||
)}
|
||||
</form.Field>
|
||||
<Button type="submit">{t("submit")}</Button>
|
||||
</form>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
@@ -19,6 +19,7 @@ import { mutateProduct } from "../utils/uxFncs";
|
||||
import { toInputDate } from "../utils/uxFncs";
|
||||
import type { ProductFormValues } from "../misc/interfaces";
|
||||
import type { productDetailsInterface } from "../misc/interfaces";
|
||||
import Cookies from "js-cookie";
|
||||
|
||||
interface ViewProductProps {
|
||||
uuid: string;
|
||||
@@ -256,7 +257,7 @@ export const ViewProduct = (props: ViewProductProps) => {
|
||||
)}
|
||||
</form.Field>
|
||||
<Typography level="body-sm" className="text-slate-500">
|
||||
{t("currency")}
|
||||
{Cookies.get("currency")}
|
||||
</Typography>
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
|
||||
@@ -14,8 +14,8 @@ import { Route as IndexRouteImport } from './routes/index'
|
||||
import { Route as AppHiddenLayoutRouteImport } from './routes/app/_hiddenLayout'
|
||||
import { Route as AppHiddenLayoutViewProductRouteImport } from './routes/app/_hiddenLayout/view-product'
|
||||
import { Route as AppHiddenLayoutStoragesRouteImport } from './routes/app/_hiddenLayout/storages'
|
||||
import { Route as AppHiddenLayoutProfileRouteImport } from './routes/app/_hiddenLayout/profile'
|
||||
import { Route as AppHiddenLayoutInventoryRouteImport } from './routes/app/_hiddenLayout/inventory'
|
||||
import { Route as AppHiddenLayoutAppSettingsRouteImport } from './routes/app/_hiddenLayout/app-settings'
|
||||
import { Route as AppHiddenLayoutAddProductRouteImport } from './routes/app/_hiddenLayout/add-product'
|
||||
|
||||
const LoginRoute = LoginRouteImport.update({
|
||||
@@ -44,17 +44,18 @@ const AppHiddenLayoutStoragesRoute = AppHiddenLayoutStoragesRouteImport.update({
|
||||
path: '/storages',
|
||||
getParentRoute: () => AppHiddenLayoutRoute,
|
||||
} as any)
|
||||
const AppHiddenLayoutProfileRoute = AppHiddenLayoutProfileRouteImport.update({
|
||||
id: '/profile',
|
||||
path: '/profile',
|
||||
getParentRoute: () => AppHiddenLayoutRoute,
|
||||
} as any)
|
||||
const AppHiddenLayoutInventoryRoute =
|
||||
AppHiddenLayoutInventoryRouteImport.update({
|
||||
id: '/inventory',
|
||||
path: '/inventory',
|
||||
getParentRoute: () => AppHiddenLayoutRoute,
|
||||
} as any)
|
||||
const AppHiddenLayoutAppSettingsRoute =
|
||||
AppHiddenLayoutAppSettingsRouteImport.update({
|
||||
id: '/app-settings',
|
||||
path: '/app-settings',
|
||||
getParentRoute: () => AppHiddenLayoutRoute,
|
||||
} as any)
|
||||
const AppHiddenLayoutAddProductRoute =
|
||||
AppHiddenLayoutAddProductRouteImport.update({
|
||||
id: '/add-product',
|
||||
@@ -67,8 +68,8 @@ export interface FileRoutesByFullPath {
|
||||
'/login': typeof LoginRoute
|
||||
'/app': typeof AppHiddenLayoutRouteWithChildren
|
||||
'/app/add-product': typeof AppHiddenLayoutAddProductRoute
|
||||
'/app/app-settings': typeof AppHiddenLayoutAppSettingsRoute
|
||||
'/app/inventory': typeof AppHiddenLayoutInventoryRoute
|
||||
'/app/profile': typeof AppHiddenLayoutProfileRoute
|
||||
'/app/storages': typeof AppHiddenLayoutStoragesRoute
|
||||
'/app/view-product': typeof AppHiddenLayoutViewProductRoute
|
||||
}
|
||||
@@ -77,8 +78,8 @@ export interface FileRoutesByTo {
|
||||
'/login': typeof LoginRoute
|
||||
'/app': typeof AppHiddenLayoutRouteWithChildren
|
||||
'/app/add-product': typeof AppHiddenLayoutAddProductRoute
|
||||
'/app/app-settings': typeof AppHiddenLayoutAppSettingsRoute
|
||||
'/app/inventory': typeof AppHiddenLayoutInventoryRoute
|
||||
'/app/profile': typeof AppHiddenLayoutProfileRoute
|
||||
'/app/storages': typeof AppHiddenLayoutStoragesRoute
|
||||
'/app/view-product': typeof AppHiddenLayoutViewProductRoute
|
||||
}
|
||||
@@ -88,8 +89,8 @@ export interface FileRoutesById {
|
||||
'/login': typeof LoginRoute
|
||||
'/app/_hiddenLayout': typeof AppHiddenLayoutRouteWithChildren
|
||||
'/app/_hiddenLayout/add-product': typeof AppHiddenLayoutAddProductRoute
|
||||
'/app/_hiddenLayout/app-settings': typeof AppHiddenLayoutAppSettingsRoute
|
||||
'/app/_hiddenLayout/inventory': typeof AppHiddenLayoutInventoryRoute
|
||||
'/app/_hiddenLayout/profile': typeof AppHiddenLayoutProfileRoute
|
||||
'/app/_hiddenLayout/storages': typeof AppHiddenLayoutStoragesRoute
|
||||
'/app/_hiddenLayout/view-product': typeof AppHiddenLayoutViewProductRoute
|
||||
}
|
||||
@@ -100,8 +101,8 @@ export interface FileRouteTypes {
|
||||
| '/login'
|
||||
| '/app'
|
||||
| '/app/add-product'
|
||||
| '/app/app-settings'
|
||||
| '/app/inventory'
|
||||
| '/app/profile'
|
||||
| '/app/storages'
|
||||
| '/app/view-product'
|
||||
fileRoutesByTo: FileRoutesByTo
|
||||
@@ -110,8 +111,8 @@ export interface FileRouteTypes {
|
||||
| '/login'
|
||||
| '/app'
|
||||
| '/app/add-product'
|
||||
| '/app/app-settings'
|
||||
| '/app/inventory'
|
||||
| '/app/profile'
|
||||
| '/app/storages'
|
||||
| '/app/view-product'
|
||||
id:
|
||||
@@ -120,8 +121,8 @@ export interface FileRouteTypes {
|
||||
| '/login'
|
||||
| '/app/_hiddenLayout'
|
||||
| '/app/_hiddenLayout/add-product'
|
||||
| '/app/_hiddenLayout/app-settings'
|
||||
| '/app/_hiddenLayout/inventory'
|
||||
| '/app/_hiddenLayout/profile'
|
||||
| '/app/_hiddenLayout/storages'
|
||||
| '/app/_hiddenLayout/view-product'
|
||||
fileRoutesById: FileRoutesById
|
||||
@@ -169,13 +170,6 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof AppHiddenLayoutStoragesRouteImport
|
||||
parentRoute: typeof AppHiddenLayoutRoute
|
||||
}
|
||||
'/app/_hiddenLayout/profile': {
|
||||
id: '/app/_hiddenLayout/profile'
|
||||
path: '/profile'
|
||||
fullPath: '/app/profile'
|
||||
preLoaderRoute: typeof AppHiddenLayoutProfileRouteImport
|
||||
parentRoute: typeof AppHiddenLayoutRoute
|
||||
}
|
||||
'/app/_hiddenLayout/inventory': {
|
||||
id: '/app/_hiddenLayout/inventory'
|
||||
path: '/inventory'
|
||||
@@ -183,6 +177,13 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof AppHiddenLayoutInventoryRouteImport
|
||||
parentRoute: typeof AppHiddenLayoutRoute
|
||||
}
|
||||
'/app/_hiddenLayout/app-settings': {
|
||||
id: '/app/_hiddenLayout/app-settings'
|
||||
path: '/app-settings'
|
||||
fullPath: '/app/app-settings'
|
||||
preLoaderRoute: typeof AppHiddenLayoutAppSettingsRouteImport
|
||||
parentRoute: typeof AppHiddenLayoutRoute
|
||||
}
|
||||
'/app/_hiddenLayout/add-product': {
|
||||
id: '/app/_hiddenLayout/add-product'
|
||||
path: '/add-product'
|
||||
@@ -195,16 +196,16 @@ declare module '@tanstack/react-router' {
|
||||
|
||||
interface AppHiddenLayoutRouteChildren {
|
||||
AppHiddenLayoutAddProductRoute: typeof AppHiddenLayoutAddProductRoute
|
||||
AppHiddenLayoutAppSettingsRoute: typeof AppHiddenLayoutAppSettingsRoute
|
||||
AppHiddenLayoutInventoryRoute: typeof AppHiddenLayoutInventoryRoute
|
||||
AppHiddenLayoutProfileRoute: typeof AppHiddenLayoutProfileRoute
|
||||
AppHiddenLayoutStoragesRoute: typeof AppHiddenLayoutStoragesRoute
|
||||
AppHiddenLayoutViewProductRoute: typeof AppHiddenLayoutViewProductRoute
|
||||
}
|
||||
|
||||
const AppHiddenLayoutRouteChildren: AppHiddenLayoutRouteChildren = {
|
||||
AppHiddenLayoutAddProductRoute: AppHiddenLayoutAddProductRoute,
|
||||
AppHiddenLayoutAppSettingsRoute: AppHiddenLayoutAppSettingsRoute,
|
||||
AppHiddenLayoutInventoryRoute: AppHiddenLayoutInventoryRoute,
|
||||
AppHiddenLayoutProfileRoute: AppHiddenLayoutProfileRoute,
|
||||
AppHiddenLayoutStoragesRoute: AppHiddenLayoutStoragesRoute,
|
||||
AppHiddenLayoutViewProductRoute: AppHiddenLayoutViewProductRoute,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
import { Settings } from "../../../pages/Settings";
|
||||
|
||||
export const Route = createFileRoute("/app/_hiddenLayout/app-settings")({
|
||||
component: RouteComponent,
|
||||
});
|
||||
|
||||
function RouteComponent() {
|
||||
return <Settings />;
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
import { createFileRoute } from '@tanstack/react-router'
|
||||
|
||||
export const Route = createFileRoute('/app/_hiddenLayout/profile')({
|
||||
component: RouteComponent,
|
||||
})
|
||||
|
||||
function RouteComponent() {
|
||||
return <div>Hello "/app/_hiddenLayout/profile"!</div>
|
||||
}
|
||||
@@ -2,6 +2,7 @@ import { API_BASE } from "../config/api.config";
|
||||
import Cookies from "js-cookie";
|
||||
import type { TFunction } from "i18next";
|
||||
import { toast } from "react-toastify";
|
||||
import { fetchSettings } from "./uxFncs";
|
||||
|
||||
export async function isAuthenticated() {
|
||||
if (Cookies.get("token")) {
|
||||
@@ -39,10 +40,14 @@ export async function signInUser(
|
||||
});
|
||||
|
||||
const response = await result.json();
|
||||
console.log(response);
|
||||
|
||||
if (result.status === 202) {
|
||||
Cookies.set("token", response.data.token);
|
||||
|
||||
const settings = await fetchSettings();
|
||||
Cookies.set("app-name", settings?.data[0].value);
|
||||
Cookies.set("currency", settings?.data[1].value);
|
||||
|
||||
return { ok: true as const };
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import Cookies from "js-cookie";
|
||||
import type {
|
||||
NewStorage,
|
||||
ProductFormValues,
|
||||
SettingsIntf,
|
||||
Storage,
|
||||
} from "../misc/interfaces";
|
||||
|
||||
@@ -229,3 +230,46 @@ export const deleteStorage = async (uuid: string) => {
|
||||
return { success: true, code: response.code };
|
||||
}
|
||||
};
|
||||
|
||||
export const mutateSettings = async (payload: SettingsIntf) => {
|
||||
const result = await fetch(`${API_BASE}/users/update-app-settings`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify(payload),
|
||||
headers: {
|
||||
Authorization: `Bearer ${Cookies.get("token") || ""}`,
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const response = await result.json();
|
||||
|
||||
if (response.code === "eu004") {
|
||||
return { success: false, code: response.code };
|
||||
}
|
||||
|
||||
if (response.code === "su003") {
|
||||
return { success: true, code: response.code };
|
||||
}
|
||||
};
|
||||
|
||||
export const fetchSettings = async () => {
|
||||
const result = await fetch(`${API_BASE}/users/settings`, {
|
||||
method: "GET",
|
||||
headers: {
|
||||
Authorization: `Bearer ${Cookies.get("token") || ""}`,
|
||||
"Content-Type": "application/json",
|
||||
Accept: "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
const response = await result.json();
|
||||
|
||||
if (response.code === "eu005") {
|
||||
return { success: false, code: response.code };
|
||||
}
|
||||
|
||||
if (response.code === "su004") {
|
||||
return { success: true, data: response.data, code: response.code };
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user