From 219a3b65620e13290ebbe8f6efe31c49a0cb49a4 Mon Sep 17 00:00:00 2001 From: konstroyer <kmiolaethz.ch> Date: Fri, 10 Jan 2025 15:53:44 +0100 Subject: [PATCH 1/3] conditional side bar --- src/pages/Belegformular.tsx | 5 +- src/pages/index.tsx | 19 ++- src/pages/root.tsx | 248 ++++++++++++++++++++++++------------ 3 files changed, 181 insertions(+), 91 deletions(-) diff --git a/src/pages/Belegformular.tsx b/src/pages/Belegformular.tsx index db1d292..84d741e 100644 --- a/src/pages/Belegformular.tsx +++ b/src/pages/Belegformular.tsx @@ -56,7 +56,10 @@ const MainForm: React.FC = () => { return ( <Container> <Typography variant="h4" component="h2" gutterBottom> - Select Form Type + Receipt Form + </Typography> + <Typography variant="body1" gutterBottom> + Please select the type of receipt you would like to submit. </Typography> <FormControl fullWidth> <InputLabel id="form-type-label">Form Type</InputLabel> diff --git a/src/pages/index.tsx b/src/pages/index.tsx index f08a031..aa3af1d 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -45,7 +45,7 @@ export default function WelcomeToQTool() { if (paymentResponse.error) { console.error("Error fetching combined payments:", paymentResponse.error); } else { - console.log("recieved data"); + console.log("received data"); console.log(paymentResponse.data.items); setLastFiveEntries(paymentResponse.data.items); console.log(lastFiveEntries); @@ -89,14 +89,14 @@ export default function WelcomeToQTool() { textAlign: "center", }} > - <Box sx={{ marginBottom: 4 }}> - <Typography variant="h4" sx={{ fontWeight: "bold" }}> - Welcome to QTool! - </Typography> - </Box> {user ? ( <> + <Box sx={{ marginBottom: 4 }}> + <Typography variant="h4" sx={{ fontWeight: "bold" }}> + Welcome to QTool {user.firstname}! + </Typography> + </Box> <Box sx={{ width: "100%", maxWidth: "600px", marginBottom: 4 }}> <Grid container spacing={2} justifyContent="center"> <Grid item xs={6}> @@ -196,6 +196,12 @@ export default function WelcomeToQTool() { </Box> </> ) : ( + <> + <Box> + <Typography variant="h4" sx={{ fontWeight: "bold" }}> + Welcome to QTool! + </Typography> + </Box> <Box sx={{ textAlign: "center" }}> <Typography variant="h6" sx={{ marginBottom: 2 }}> Please log in to access your dashboard. @@ -207,6 +213,7 @@ export default function WelcomeToQTool() { </Button> </Link> </Box> + </> )} </Container> ); diff --git a/src/pages/root.tsx b/src/pages/root.tsx index f085fdb..0a4db0e 100644 --- a/src/pages/root.tsx +++ b/src/pages/root.tsx @@ -15,114 +15,156 @@ import { ListItemText, List, Drawer, - Checkbox, - FormControlLabel, Divider, } from "@mui/material"; import { Outlet, useLocation, useNavigate } from "react-router-dom"; import { - Checklist, - Groups, Home, - Login, - Logout, - Menu, - Payment, - Settings, - ShoppingCart, ReceiptLong, - CreditScore, - Summarize, ViewList, PlaylistRemove, Reorder, Category, Extension, - ShowChart, AccountTree, School, + Settings, + Login, + Logout, + Menu, + ShowChart, ViewListTwoTone, } from "@mui/icons-material"; -import ReceiptIcon from "@mui/icons-material/Receipt"; // Import the Receipt icon +import {authGetBasicUserInfo} from "../client/services.gen"; import { Link } from "react-router-dom"; - import AmivLogoSVG from "../assets/amiv.svg"; import AmivWheelSVG from "../assets/amiv-wheel.svg"; -import Callback from "../Callback"; -const navContent = [ - { - path: "/Belegformular", - name: "Receipt Form", - icon: <ReceiptLong />, - }, - { path: "/combinedList", - name: "My Payments", - icon: <Reorder /> }, - { - path: "/KstEval", - name: "KST | Cost Center Evaluation", - icon: <ShowChart />, - }, - { - path: "/UncheckedPayments", - name: "Open Requests", - icon: <PlaylistRemove />, - }, +const sections = [ { - path: "/ownList", - name: "Own Requests", - icon: <ViewList />, + title: "General", + items: [ + { + path: "/", + name: "Home", + icon: <Home />, + }, + { + path: "/Belegformular", + name: "Receipt Form", + icon: <ReceiptLong />, + }, + { + path: "/ownList", + name: "My Requests", + icon: <ViewList />, + }, + { + path: "/KstEval", + name: "KST | Cost Center Evaluation", + icon: <ShowChart />, + }, + { + path: "/kstResponsibleCreditorList", + name: "KST Responsible List", + icon: <ViewListTwoTone />, + }, + ], }, { - path: "/kstResponsibleCreditorList", - name: "KST Responsible List", - icon: <ViewListTwoTone />, + title: "Receipt Management", + items: [ + { + path: "/UncheckedPayments", + name: "Open Requests", + icon: <PlaylistRemove />, + }, + { + path: "/combinedList", + name: "All Payments", + icon: <Reorder />, + }, + { + path: "/creditlist", + name: "Credit List", + icon: <ViewList />, + }, + ], }, { - path: "/creditlist", - name: "Credit List", - icon: <ViewList />, + title: "Edit Qtool", + items: [ + { + path: "/GenerateItem", + name: "Add Invoice Item", + icon: <Category />, + }, + { + path: "/GenerateLedger", + name: "Add Ledger", + icon: <Extension />, + }, + { + path: "/GenerateKst", + name: "Add Cost Center | KST", + icon: <AccountTree />, + }, + ], }, { - path: "/GenerateItem", - name: "Add Item", - icon: <Category />, + title: "Other", + items: [ + { + path: "/Onboarding", + name: "Onboarding", + icon: <School />, + }, + ], }, - { - path: "/GenerateLedger", - name: "Add Ledger", - icon: <Extension />, - }, - { - path: "/GenerateKst", - name: "Add Cost Center | KST", - icon: <AccountTree />, - }, - { - path: "/Onboarding", - name: "Onboarding", - icon: <School />, - }, -] as { path: string; name: string; icon: React.ReactNode }[]; +]; + +function NavigationList({ user }: { user: any }) { + // Ensure sections are filtered based on user.role + const filteredSections = sections.filter((section) => { + if (section.title === "General") { + return true; // Always include the General section + } + if (section.title === "Receipt Management" && user?.role === "auditor") { + return true; // Include Receipt Management for auditors + } + return user?.role === "quaestor"; // Include other sections only for quaestors + }); -function NavigationList() { return ( <> - <List> - {navContent.map((item, index) => ( - <ListItem key={index}> - <ListItemButton component={Link} to={item.path}> - <ListItemIcon>{item.icon}</ListItemIcon> - <ListItemText primary={item.name} /> - </ListItemButton> - </ListItem> - ))} - </List> + {user ? ( + filteredSections.map((section, sectionIndex) => ( + <Box key={sectionIndex} sx={{ marginBottom: 2 }}> + <Typography variant="subtitle1" sx={{ paddingLeft: 2, paddingTop: 1 }}> + {section.title} + </Typography> + <List> + {section.items.map((item, index) => ( + <ListItem key={index}> + <ListItemButton component={Link} to={item.path}> + <ListItemIcon>{item.icon}</ListItemIcon> + <ListItemText primary={item.name} /> + </ListItemButton> + </ListItem> + ))} + </List> + {sectionIndex < filteredSections.length - 1 && <Divider />} + </Box> + )) + ) : ( + <Typography></Typography> + )} </> ); } + + function DesktopAppBar({ sx, toggleDrawer, @@ -136,13 +178,19 @@ function DesktopAppBar({ onLogin: () => void; onLogout: () => void; }) { + const navigate = useNavigate(); return ( - <AppBar position="static" sx={sx}> + <AppBar position="fixed" sx={sx}> <Toolbar> <IconButton onClick={toggleDrawer}> <Menu /> </IconButton> - <Typography variant="h6" component="div" sx={{ flexGrow: 1 }}> + <Typography + variant="h6" + component="div" + sx={{ flexGrow: 1, cursor: "pointer" }} + onClick={() => navigate("/")} + > <img src={AmivLogoSVG} alt="AMIV Logo" style={{ height: "1.5em" }} /> </Typography> <IconButton> @@ -175,13 +223,19 @@ function MobileAppBar({ onLogin: () => void; onLogout: () => void; }) { + const navigate = useNavigate(); return ( - <AppBar position="static" sx={sx}> + <AppBar position="fixed" sx={sx}> <Toolbar> <IconButton onClick={toggleDrawer}> <Menu /> </IconButton> - <Typography variant="h6" component="div" sx={{ flexGrow: 1 }}> + <Typography + variant="h6" + component="div" + sx={{ flexGrow: 1, cursor: "pointer" }} + onClick={() => navigate("/")} + > <img src={AmivWheelSVG} alt="AMIV Wheel" @@ -202,6 +256,7 @@ function MobileAppBar({ ); } + function App() { const theme = useTheme(); const bigScreen = useMediaQuery(theme.breakpoints.up("md")); @@ -210,25 +265,48 @@ function App() { const [drawerOpen, setDrawerOpen] = useState<boolean>(false); const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false); + const [user, setUser] = useState<any | null>(null); + const [isFetchingUser, setIsFetchingUser] = useState(true); + // Function to fetch user info and data + const fetchUser = async () => { + try { + setIsFetchingUser(true); + // Fetch user info + const userResponse = await authGetBasicUserInfo(); + if (userResponse.error) { + console.error("Failed to fetch user info:", userResponse.error); + setUser(null); + } else { + setUser(userResponse.data); + } + } catch (error) { + console.error("Error fetching data:", error); + setUser(null); + } finally { + setIsFetchingUser(false); + } + }; + + // Fetch data on mount and when user state changes + useEffect(() => { + fetchUser(); + }, []); const toggleDrawer = () => { setDrawerOpen((o) => !o); }; - // Check authentication status on mount and when location changes useEffect(() => { const token = localStorage.getItem("access_token"); setIsAuthenticated(!!token); }, [location]); const handleLogin = () => { - // Redirect to the backend login endpoint - window.location.href = import.meta.env.VITE_API_BASE_URL + "api/login"; + fetchUser(); }; const handleLogout = () => { - // Remove token and update state localStorage.removeItem("access_token"); setIsAuthenticated(false); navigate("/"); @@ -260,11 +338,13 @@ function App() { onClose={toggleDrawer} > <Box sx={{ width: "100%" }}> - <NavigationList /> + <NavigationList user = {user}/> </Box> </Drawer> - <Outlet /> + <Box sx={{ marginTop: "64px" }}> + <Outlet /> + </Box> </> ); } -- GitLab From 72c23ad6a9b73065fdf9bc91c9b38329eef42956 Mon Sep 17 00:00:00 2001 From: konstroyer <kmiola@ethz.ch> Date: Sun, 12 Jan 2025 17:14:18 +0100 Subject: [PATCH 2/3] various changes, delete button, adapted onboarding, moved apply changes button, --- src/components/GenericEditableTable.tsx | 3 + src/components/ObjectEditor.tsx | 25 +++-- src/main.tsx | 24 +++++ src/pages/Bills.tsx | 22 +++++ src/pages/CreditPayment.tsx | 26 ++++- src/pages/EditBills.tsx | 17 +++- src/pages/EditCreditPayment.tsx | 17 +++- src/pages/EditInternalTransfer.tsx | 16 ++- src/pages/EditReimbursement.tsx | 18 ++++ src/pages/InternalTransfer.tsx | 33 ++++++- src/pages/Onboarding.tsx | 7 +- src/pages/OnboardingQuiz.tsx | 28 ++++-- src/pages/OwnList.tsx | 12 ++- src/pages/index.tsx | 124 ++++++++++++++---------- src/pages/root.tsx | 36 ++++++- 15 files changed, 321 insertions(+), 87 deletions(-) diff --git a/src/components/GenericEditableTable.tsx b/src/components/GenericEditableTable.tsx index 60ac0de..54bf731 100644 --- a/src/components/GenericEditableTable.tsx +++ b/src/components/GenericEditableTable.tsx @@ -48,6 +48,8 @@ function getEditComponent( id: string, handleClose: () => void, ): React.ReactNode { + console.log("type", type); + console.log("id", id); switch (type) { case "Reimbursement": return ( @@ -194,6 +196,7 @@ const GenericEditableTable: React.FC<EditableTableProps> = ({ }; const defaultColumns = [ + { name: "type", label: "Type" }, { name: "id", label: "ID" }, { name: "name", label: "Name" }, diff --git a/src/components/ObjectEditor.tsx b/src/components/ObjectEditor.tsx index 0ca7960..f3912f4 100644 --- a/src/components/ObjectEditor.tsx +++ b/src/components/ObjectEditor.tsx @@ -2,6 +2,7 @@ import { Paper, Stack, Typography, + Box, Button, TextField, FormControlLabel, @@ -191,9 +192,6 @@ export default function ObjectEditor<ItemT>({ {deleter && ( <Button onClick={() => setDeleteDialogOpen(true)}>Delete</Button> )} - <Button onClick={handleSubmit} disabled={changedFields.size === 0}> - Apply Changes - </Button> </ButtonGroup> </Stack> <Stack spacing={1}> @@ -312,6 +310,21 @@ export default function ObjectEditor<ItemT>({ })} </Stack> </Paper> + <Box sx={{ display: 'flex', justifyContent: 'center', margin: 2 }}> + <Button + variant="contained" + onClick={handleSubmit} + disabled={changedFields.size === 0} + sx={{ + padding: 2, + fontSize: '1.2rem', + width: '100%', + maxWidth: '400px', + }} + > + Submit + </Button> + </Box> <Snackbar open={showStatusAlert} autoHideDuration={4000} @@ -327,7 +340,6 @@ export default function ObjectEditor<ItemT>({ : statusAlertFailReason} </Alert> </Snackbar> - {/* Optional: Delete Confirmation Dialog */} {deleter && ( <Dialog open={deleteDialogOpen} @@ -336,8 +348,7 @@ export default function ObjectEditor<ItemT>({ <DialogTitle>Confirm Deletion</DialogTitle> <DialogContent> <DialogContentText> - Are you sure you want to delete this item? This action cannot be - undone. + Are you sure you want to delete this item? This action cannot be undone. </DialogContentText> </DialogContent> <DialogActions> @@ -361,4 +372,4 @@ export default function ObjectEditor<ItemT>({ )} </Container> ); -} +} \ No newline at end of file diff --git a/src/main.tsx b/src/main.tsx index 2e41050..580521d 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -16,6 +16,10 @@ import CombinedPaymentsPage from "./pages/CombinedList"; import Belegformular, { addLoader as addCreditPaymentLoader, } from "./pages/Belegformular"; +import Reimbursement from "./pages/Reimbursement"; +import Bills from "./pages/Bills"; +import CreditPayment from "./pages/CreditPayment"; +import InternalTransfer from "./pages/InternalTransfer"; import EditCreditPayment from "./pages/EditCreditPayment"; import GenerateItem from "./pages/GenerateItem"; import GenerateLedger from "./pages/GenerateLedger"; @@ -45,6 +49,26 @@ const router = createBrowserRouter([ element: <Belegformular />, loader: addCreditPaymentLoader, }, + { + path: "Reimbursement", + element: <Reimbursement />, + loader: addCreditPaymentLoader, + }, + { + path: "CreditPayment", + element: <CreditPayment />, + loader: addCreditPaymentLoader, + }, + { + path: "Bills", + element: <Bills />, + loader: addCreditPaymentLoader, + }, + { + path: "InternalTransfer", + element: <InternalTransfer />, + loader: addCreditPaymentLoader, + }, { path: "GenerateItem", element: <GenerateItem />, diff --git a/src/pages/Bills.tsx b/src/pages/Bills.tsx index 753a622..f7d3607 100644 --- a/src/pages/Bills.tsx +++ b/src/pages/Bills.tsx @@ -17,6 +17,27 @@ export function generateFieldConfigs( ledger: Ledger[], q_mode: boolean = false, ): FieldConfig<BillCreate>[] { + let qfields = [] as FieldConfig<BillCreate>[]; + if (q_mode === true) { + qfields = [ + { + name: "textcomment", + label: "text comment", + type: FieldType.COMMENT, + comment: "these fields are only for the quästor:", + }, + { name: "creditor.qcomment", label: "qcomment", type: FieldType.STRING }, + { name: "creditor.name", label: "name", type: FieldType.STRING }, + { name: "creditor.creator_id", label: "creator", type: FieldType.STRING }, + { + name: "creditor.accounting_year", + label: "accounting_year", + type: FieldType.NUMERIC, + }, + { name: "creditor.q_check", label: "q_check", type: FieldType.BOOLEAN }, + ]; + } + return [ { name: "creditor.comment", label: "Description", type: FieldType.STRING }, { name: "creditor.amount", label: "Amount", type: FieldType.NUMERIC }, @@ -67,6 +88,7 @@ export function generateFieldConfigs( { name: "iban", label: "Iban", type: FieldType.STRING }, { name: "reciept", label: "receipt", type: FieldType.FILE }, { name: "comment", label: "comment", type: FieldType.STRING }, + ...qfields, ]; } diff --git a/src/pages/CreditPayment.tsx b/src/pages/CreditPayment.tsx index e71e782..ccaf359 100644 --- a/src/pages/CreditPayment.tsx +++ b/src/pages/CreditPayment.tsx @@ -23,11 +23,31 @@ export function generateFieldConfigs( ledger: Ledger[], qmode: boolean, ): FieldConfig<CreditPaymentCreate>[] { + let qfields = [] as FieldConfig<CreditPaymentCreate>[]; + if (qmode === true) { + qfields = [ + { + name: "textcomment", + label: "text comment", + type: FieldType.COMMENT, + comment: "these fields are only for the quästor:", + }, + { name: "creditor.qcomment", label: "qcomment", type: FieldType.STRING }, + { name: "creditor.name", label: "name", type: FieldType.STRING }, + { name: "creditor.creator_id", label: "creator", type: FieldType.STRING }, + { name: "recipient", label: "recipient", type: FieldType.STRING }, + { + name: "creditor.accounting_year", + label: "accounting_year", + type: FieldType.NUMERIC, + }, + { name: "creditor.q_check", label: "q_check", type: FieldType.BOOLEAN }, + ]; + } return [ { name: "creditor.comment", label: "Description", type: FieldType.STRING }, { name: "creditor.amount", label: "Amount", type: FieldType.NUMERIC }, { name: "creditor.currency", label: "Currency", type: FieldType.STRING }, - { name: "creditor.kst_id", label: "KST | Cost Center", @@ -53,7 +73,9 @@ export function generateFieldConfigs( { label: "Quaestor", value: Card.QUAESTOR }, ], }, - { name: "reciept", label: "reciept", type: FieldType.FILE }, + { name: "reciept", label: "receipt", type: FieldType.FILE }, + { name: "creditor.comment", label: "comment", type: FieldType.STRING }, + ...qfields, ]; } diff --git a/src/pages/EditBills.tsx b/src/pages/EditBills.tsx index bb11a04..d020710 100644 --- a/src/pages/EditBills.tsx +++ b/src/pages/EditBills.tsx @@ -1,5 +1,5 @@ import { CircularProgress, Container } from "@mui/material"; -import { billsReadBill, billsUpdateBill } from "../client/services.gen"; +import { billsReadBill, billsUpdateBill, billsDeleteBill } from "../client/services.gen"; import { BillCreate, Kst, @@ -99,7 +99,19 @@ export default function EditBills( } }; - const fieldConfig = generateFieldConfigs(kst, ledger); + const deleter = async () => { + const response = await billsDeleteBill({ + path: { id: idstring }, + }); + if (response.error) { + throw response.error; + } else { + // Optionally navigate or handle success + return; + } + } + + const fieldConfig = generateFieldConfigs(kst, ledger,true); if (loading || !initialElement) { return ( @@ -115,6 +127,7 @@ export default function EditBills( fieldConfigs={fieldConfig} header="Edit Credit Payment" submitter={submitter} + deleter={deleter} initial={initialElement} /> </Container> diff --git a/src/pages/EditCreditPayment.tsx b/src/pages/EditCreditPayment.tsx index 01fb8cd..ac008fd 100644 --- a/src/pages/EditCreditPayment.tsx +++ b/src/pages/EditCreditPayment.tsx @@ -4,6 +4,7 @@ import { creditPaymentsCreateCreditPayment, creditPaymentsReadCreditPayment, creditPaymentsUpdateCreditPayment, + creditPaymentsDeleteCreditPayment } from "../client/services.gen"; import { Card, @@ -80,7 +81,7 @@ export default function EditCreditPayment( const submitter = async (changes: CreditPaymentPublic_Input) => { changes.reciept = await RecieptHandler(changes.reciept); - const response = await creditPaymentsUpdateCreditPayment({ + const response = await creditPaymentsDeleteCreditPayment({ body: changes, path: { id: idstring }, }); @@ -91,8 +92,19 @@ export default function EditCreditPayment( return; } }; + const deleter = async () => { + const response = await creditPaymentsDeleteCreditPayment({ + path: { id: idstring }, + }); + if (response.error) { + throw response.error; + } else { + // Optionally navigate or handle success + return; + } + } - const fieldConfig = generateFieldConfigs(kst, ledger); + const fieldConfig = generateFieldConfigs(kst, ledger, true); if (loading || !initialElement) { return ( @@ -108,6 +120,7 @@ export default function EditCreditPayment( fieldConfigs={fieldConfig} header="Edit Credit Payment" submitter={submitter} + deleter={deleter} initial={initialElement} /> </Container> diff --git a/src/pages/EditInternalTransfer.tsx b/src/pages/EditInternalTransfer.tsx index 947ac73..b7d32dd 100644 --- a/src/pages/EditInternalTransfer.tsx +++ b/src/pages/EditInternalTransfer.tsx @@ -3,6 +3,7 @@ import { internalTransfersUpdateInternalTransfer, internalTransfersReadInternalTransfer, InternalTransfersUpdateInternalTransfer, + internalTransfersDeleteInternalTransfer } from "../client/services.gen"; import { InternalTransferCreate, @@ -96,7 +97,19 @@ export default function EditInternalTransfers( } }; - const fieldConfig = generateFieldConfigs(kst, ledger); + const deleter = async () => { + const response = await internalTransfersDeleteInternalTransfer({ + path: { id: idstring }, + }); + if (response.error) { + throw response.error; + } else { + // Optionally navigate or handle success + return; + } + } + + const fieldConfig = generateFieldConfigs(kst, ledger,true); if (loading || !initialElement) { return ( @@ -112,6 +125,7 @@ export default function EditInternalTransfers( fieldConfigs={fieldConfig} header="Edit Internal Transfer" submitter={submitter} + deleter={deleter} initial={initialElement} /> </Container> diff --git a/src/pages/EditReimbursement.tsx b/src/pages/EditReimbursement.tsx index 9cc2643..badc014 100644 --- a/src/pages/EditReimbursement.tsx +++ b/src/pages/EditReimbursement.tsx @@ -2,7 +2,9 @@ import { CircularProgress, Container } from "@mui/material"; import { reimbursementsUpdateReimbursement, reimbursementsReadReimbursement, + reimbursementsDeleteReimbursement, filesUploadFile, + } from "../client/services.gen"; import { ReimbursementCreate, @@ -23,6 +25,7 @@ import { Kst_title, Ledger_title } from "../components/Titles"; import { useEffect, useState } from "react"; import { generateFieldConfigs } from "./Reimbursement"; import RecieptHandler from "../components/RecieptHandler"; +import { changeSectionValueFormat } from "@mui/x-date-pickers/internals/hooks/useField/useField.utils"; export default function EditReimbursement(propIdString: string) { const { idstring: urlidstring } = useParams<{ idstring: string }>(); @@ -88,8 +91,22 @@ export default function EditReimbursement(propIdString: string) { } }; + const deleter = async () => { + const response = await reimbursementsDeleteReimbursement({ + path: { id: idstring }, + }); + if (response.error) { + throw response.error; + } else { + // Optionally navigate or handle success + return; + } + } + + const fieldConfig = generateFieldConfigs(kst, ledger, true); + if (loading || !initialElement) { return ( <Container> @@ -104,6 +121,7 @@ export default function EditReimbursement(propIdString: string) { fieldConfigs={fieldConfig} header="Edit Credit Payment" submitter={submitter} + deleter={deleter} initial={initialElement} /> </Container> diff --git a/src/pages/InternalTransfer.tsx b/src/pages/InternalTransfer.tsx index 23975e9..6870d72 100644 --- a/src/pages/InternalTransfer.tsx +++ b/src/pages/InternalTransfer.tsx @@ -35,22 +35,45 @@ export function generateFieldConfigs( ledger: Ledger[], qmode: boolean, ): FieldConfig<InternalTransferCreate>[] { + let qfields = [] as FieldConfig<InternalTransferCreate>[]; + if (qmode === true) { + qfields = [ + { + name: "textcomment", + label: "text comment", + type: FieldType.COMMENT, + comment: "these fields are only for the quästor:", + }, + { name: "creditor.qcomment", label: "qcomment", type: FieldType.STRING }, + { name: "creditor.name", label: "name", type: FieldType.STRING }, + { name: "creditor.creator_id", label: "creator", type: FieldType.STRING }, + { + name: "creditor.accounting_year", + label: "accounting_year", + type: FieldType.NUMERIC, + }, + { name: "creditor.q_check", label: "q_check", type: FieldType.BOOLEAN }, + + ]; + } + return [ + { name: "creditor.comment", label: "Description", type: FieldType.STRING }, { name: "debitor.kst_id", - label: "source kst", + label: "Source Cost Center (KST)", type: FieldType.STRING, items: kst.map((k) => ({ label: Kst_title(k), value: k.id ? k.id : "" })), }, { name: "creditor.kst_id", - label: "destination kst", + label: "Destination Cost Center (KST)", type: FieldType.STRING, items: kst.map((k) => ({ label: Kst_title(k), value: k.id ? k.id : "" })), }, - { name: "creditor.amount", label: "amount", type: FieldType.NUMERIC }, - { name: "creditor.currency", label: "währung", type: FieldType.STRING }, - { name: "creditor.comment", label: "kommentar", type: FieldType.STRING }, + { name: "creditor.amount", label: "Amount", type: FieldType.NUMERIC }, + { name: "creditor.currency", label: "Currency", type: FieldType.STRING }, + ...qfields, ]; } diff --git a/src/pages/Onboarding.tsx b/src/pages/Onboarding.tsx index b37ee0e..a05615d 100644 --- a/src/pages/Onboarding.tsx +++ b/src/pages/Onboarding.tsx @@ -18,6 +18,12 @@ import ObjectEditor, { } from "../components/ObjectEditor"; const fieldConfig: FieldConfig<DbUserCreate>[] = [ + { + name: "textcomment", + label: "text comment", + type: FieldType.COMMENT, + comment: "Please enter your bank details. Any reimbursements will be sent to this account.", + }, { name: "iban", label: "IBAN", type: FieldType.STRING }, { name: "address.name", label: "Name", type: FieldType.STRING }, @@ -90,7 +96,6 @@ export default function OnboardingPage() { return ( <Container> - Please enter your bank details. Any reimbursements will be sent to this account. Once you have entered your bank details, you will be able to submit your first reimbursement. <ObjectEditor fieldConfigs={fieldConfig} header="Onboarding" diff --git a/src/pages/OnboardingQuiz.tsx b/src/pages/OnboardingQuiz.tsx index 8200190..c54e980 100644 --- a/src/pages/OnboardingQuiz.tsx +++ b/src/pages/OnboardingQuiz.tsx @@ -74,11 +74,26 @@ export default function OnboardingCourse() { correctAnswer: "After the request was accepted", }, { - id: 7, - title: "Warning!", - description: "Use QTool responsibly and try your best to do everything correctly. The AMIV treasury will be very grateful. In the end, we all do this work voluntarily. Finally, every request will be thoroughly checked by the AMIV treasury; any fraudulent behavior will have consequences.", - isFinalPage: true, - } + "id": 7, + "title": "Additional Information", + "description": "You need to submit one form for EACH receipt. You CANNOT group multiple receipts. Additionally, receipts must be entered into QTool within 7 days of the purchase.", + "question": "What is the ideal sequence of actions when you spend money for AMIV? The context is a big event where you use an AMIV credit card to make some purchases.", + "options":[ + "After I make all purchases, I throw the receipts in the bin and have fun at the event.", + "After each purchase, I take a high-quality picture of the receipt, and within 7 days of the purchase, I fill out a form for each receipt and upload it.", + "I keep the receipts in my wallet and fill out the forms when I have time.", + "After I make all purchases, I put the receipts next to each other, take a picture, and fill out one form for all receipts." + ], + "correctAnswer": "After each purchase, I take a high-quality picture of the receipt, and within 7 days of the purchase, I fill out a form for each receipt and upload it.", + }, + + { + "id": 8, + "title": "Warning!", + "description": "Use QTool responsibly and make every effort to ensure accuracy. The AMIV treasury will greatly appreciate your diligence. Remember, we all do this work voluntarily. Lastly, every request will be thoroughly reviewed by the AMIV treasury, and any fraudulent behavior will result in consequences.", + "isFinalPage": true + } + ]; // State @@ -173,8 +188,9 @@ export default function OnboardingCourse() { onChange={() => setTermsAccepted(!termsAccepted)} /> <Typography variant="body2"> - I am aware of my responsibilities and will use QTool responsibly. + I acknowledge my responsibilities and commit to using QTool responsibly. </Typography> + </Box> <Button diff --git a/src/pages/OwnList.tsx b/src/pages/OwnList.tsx index cf50582..6d88373 100644 --- a/src/pages/OwnList.tsx +++ b/src/pages/OwnList.tsx @@ -3,6 +3,7 @@ import { useLoaderData } from "react-router-dom"; import { combinedReadOwnCombinedPayments } from "../client/services.gen"; import GenericEditableTable from "../components/GenericEditableTable"; import { CombinedCreditor } from "../client/types.gen"; +import { Container, Typography } from '@mui/material'; const OwnList: React.FC = () => { const { kst, ledger, user } = useLoaderData() as { @@ -45,23 +46,26 @@ const OwnList: React.FC = () => { ledger.find((l) => l.id === item.creditor?.ledger_id)?.name_de || "Unknown", creditor__currency: item.creditor?.currency, - creator: user.nethz, type: item.type, id: item.id, reference: item.reference, - iban: item.iban, comment: item.creditor.comment, - reimbursement__recipient: item.reimbursement__recipient, })); }; return ( + <Container> + <Typography variant="h4" component="h1" gutterBottom> + My Requests + </Typography> + <GenericEditableTable - title="All Submissions" + title="My Requests" fetchFunction={fetchCombinedPayments} kst={kst} ledger={ledger} /> + </Container> ); }; diff --git a/src/pages/index.tsx b/src/pages/index.tsx index aa3af1d..fdf3c77 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -97,58 +97,70 @@ export default function WelcomeToQTool() { Welcome to QTool {user.firstname}! </Typography> </Box> - <Box sx={{ width: "100%", maxWidth: "600px", marginBottom: 4 }}> - <Grid container spacing={2} justifyContent="center"> - <Grid item xs={6}> - <Link href="/Belegformular" underline="none"> - <Button - variant="contained" - color="primary" - size="large" - sx={{ width: "100%" }} - > - Reimbursement Request - </Button> - </Link> - </Grid> - <Grid item xs={6}> - <Link href="/Belegformular" underline="none"> - <Button - variant="contained" - color="secondary" - size="large" - sx={{ width: "100%" }} - > - Credit Card Form - </Button> - </Link> - </Grid> - <Grid item xs={6}> - <Link href="/CombinedList" underline="none"> - <Button - variant="contained" - color="success" - size="large" - sx={{ width: "100%" }} - > - My Requests and Payments - </Button> - </Link> - </Grid> - <Grid item xs={6}> - <Link href="/support" underline="none"> - <Button - variant="contained" - color="info" - size="large" - sx={{ width: "100%" }} - > - Settings - </Button> - </Link> - </Grid> + <Box sx={{ width: "100%", maxWidth: "600px", marginBottom: 4 }}> + <Grid container spacing={2} justifyContent="center"> + <Grid item xs={6}> + <Link href="/Belegformular" underline="none"> + <Button + variant="contained" + size="large" + sx={{ + width: "100%", + backgroundColor: "#d8202a", // Kahoot red + "&:hover": { backgroundColor: "#c11c24" } // Slightly darker on hover + }} + > + Reimbursement Request + </Button> + </Link> </Grid> - </Box> + <Grid item xs={6}> + <Link href="/Belegformular" underline="none"> + <Button + variant="contained" + size="large" + sx={{ + width: "100%", + backgroundColor: "#1368ce", // Kahoot blue + "&:hover": { backgroundColor: "#105bb4" } // Slightly darker on hover + }} + > + Credit Card Form + </Button> + </Link> + </Grid> + <Grid item xs={6}> + <Link href="/CombinedList" underline="none"> + <Button + variant="contained" + size="large" + sx={{ + width: "100%", + backgroundColor: "#ffc028", // Kahoot yellow + "&:hover": { backgroundColor: "#e0a520" } // Slightly darker on hover + }} + > + My Requests and Payments + </Button> + </Link> + </Grid> + <Grid item xs={6}> + <Link href="/support" underline="none"> + <Button + variant="contained" + size="large" + sx={{ + width: "100%", + backgroundColor: "#2baa41", // Kahoot green + "&:hover": { backgroundColor: "#249136" } // Slightly darker on hover + }} + > + Settings + </Button> + </Link> + </Grid> + </Grid> + </Box> <Box sx={{ maxWidth: "600px", marginBottom: 4 }}> <Typography variant="body1"> For more information, please visit the official QTool documentation linked below. If @@ -170,7 +182,15 @@ export default function WelcomeToQTool() { target="_blank" rel="noopener noreferrer" > - <Button variant="contained" color="warning" size="large" sx={{ width: "300px" }}> + <Button + variant="contained" + size="large" + sx={{ + width: "300px", + backgroundColor: "#46178f", // Purple color + "&:hover": { backgroundColor: "#3d157f" } // Slightly darker purple on hover + }} + > QTool Documentation </Button> </Link> diff --git a/src/pages/root.tsx b/src/pages/root.tsx index 0a4db0e..b296f5c 100644 --- a/src/pages/root.tsx +++ b/src/pages/root.tsx @@ -34,6 +34,9 @@ import { Menu, ShowChart, ViewListTwoTone, + CreditCard, + Description, + SyncAlt, } from "@mui/icons-material"; import {authGetBasicUserInfo} from "../client/services.gen"; import { Link } from "react-router-dom"; @@ -49,11 +52,6 @@ const sections = [ name: "Home", icon: <Home />, }, - { - path: "/Belegformular", - name: "Receipt Form", - icon: <ReceiptLong />, - }, { path: "/ownList", name: "My Requests", @@ -68,6 +66,31 @@ const sections = [ path: "/kstResponsibleCreditorList", name: "KST Responsible List", icon: <ViewListTwoTone />, + } + ], + }, + { + title: "Requests", + items: [ + { + path: "/Reimbursement", + name: "Reimbursement", + icon: <ReceiptLong />, + }, + { + path: "/CreditPayment", + name: "Credit Card Approval", + icon: <CreditCard />, + }, + { + path: "/Bills", + name: "Bill Payment", + icon: <Description />, + }, + { + path: "/InternalTransfer", + name: "Internal Transfer", + icon: <SyncAlt />, }, ], }, @@ -129,6 +152,9 @@ function NavigationList({ user }: { user: any }) { if (section.title === "General") { return true; // Always include the General section } + if (section.title === "Requests") { + return true; // Always include the Requests section + } if (section.title === "Receipt Management" && user?.role === "auditor") { return true; // Include Receipt Management for auditors } -- GitLab From 4ce3af88b6293cc8007c8dadbff3627fae5863e0 Mon Sep 17 00:00:00 2001 From: konstroyer <kmiola@ethz.ch> Date: Sun, 12 Jan 2025 17:02:05 +0000 Subject: [PATCH 3/3] small textchange in edit files --- src/pages/EditBills.tsx | 2 +- src/pages/EditReimbursement.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/pages/EditBills.tsx b/src/pages/EditBills.tsx index d020710..b6ff651 100644 --- a/src/pages/EditBills.tsx +++ b/src/pages/EditBills.tsx @@ -125,7 +125,7 @@ export default function EditBills( <Container> <ObjectEditor fieldConfigs={fieldConfig} - header="Edit Credit Payment" + header="Edit Bill Payment" submitter={submitter} deleter={deleter} initial={initialElement} diff --git a/src/pages/EditReimbursement.tsx b/src/pages/EditReimbursement.tsx index badc014..136ef5c 100644 --- a/src/pages/EditReimbursement.tsx +++ b/src/pages/EditReimbursement.tsx @@ -119,7 +119,7 @@ export default function EditReimbursement(propIdString: string) { <Container> <ObjectEditor fieldConfigs={fieldConfig} - header="Edit Credit Payment" + header="Edit reimbursement" submitter={submitter} deleter={deleter} initial={initialElement} -- GitLab