Skip to content
This repository has been archived by the owner on Aug 23, 2024. It is now read-only.

Commit

Permalink
feat: add operator roles and checks
Browse files Browse the repository at this point in the history
fix: #12
affected: #9 #10
  • Loading branch information
yehezkieldio committed Feb 12, 2024
1 parent bfae1bd commit 7404d1d
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 15 deletions.
3 changes: 3 additions & 0 deletions apps/app/src/components/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ setupIonicReact();

const App: React.FC = () => {
const [operator, setOperator] = useState(null);
const [role, setRole] = useState(null);

return (
<IonApp>
Expand All @@ -35,6 +36,8 @@ const App: React.FC = () => {
value={{
operator: operator,
setOperator: setOperator,
role: role,
setRole: setRole,
}}
>
<Route path="/onboarding" render={() => <Onboarding />} exact={true} />
Expand Down
17 changes: 12 additions & 5 deletions apps/app/src/components/operator-tabs.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import { Redirect, Route } from "react-router-dom";
import { IonRouterOutlet, IonTabs, IonTabBar, IonTabButton, IonLabel } from "@ionic/react";
import { Icons } from "@trashtrack/ui";
import { Icons, OperatorContext } from "@trashtrack/ui";

import OperatorDashboard from "../pages/operator/dashboard";
import OperatorTrashbinDisplay from "../pages/operator/trash-bin/display";
import OperatorUserDisplay from "../pages/operator/user/display";
import { useContext } from "react";

const OperatorTabs: React.FC = () => {
const operator = useContext(OperatorContext);

const isAdmin = operator.role === "admin";

return (
<IonTabs>
<IonRouterOutlet animated={false} mode="ios">
Expand All @@ -24,10 +29,12 @@ const OperatorTabs: React.FC = () => {
<Icons.trash strokeWidth={1} className="pt-2 w-[32px] h-[30px]" />
<IonLabel className="pt-2">Trashbin</IonLabel>
</IonTabButton>
<IonTabButton tab="tab3" href="/operator/tabs/user">
<Icons.user strokeWidth={1} className="pt-2 w-[32px] h-[30px]" />
<IonLabel className="pt-2">User</IonLabel>
</IonTabButton>
{isAdmin && (
<IonTabButton tab="tab3" href="/operator/tabs/user">
<Icons.user strokeWidth={1} className="pt-2 w-[32px] h-[30px]" />
<IonLabel className="pt-2">User</IonLabel>
</IonTabButton>
)}
</IonTabBar>
</IonTabs>
);
Expand Down
7 changes: 7 additions & 0 deletions apps/app/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
/**
* Notes from the lead developer of this codebase:
* "Never gonna touch Capacitor again, after this competition is over. Such a mess.
* I'll be considering moving to Expo, or Flutter, or just plain old web."
* - @elizielx
*/

import { StrictMode } from "react";
import * as ReactDOM from "react-dom/client";
import { ErrorBoundary } from "react-error-boundary";
Expand Down
9 changes: 9 additions & 0 deletions apps/app/src/pages/operator/dashboard.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import { IonContent, IonPage } from "@ionic/react";
import { Card, CardContent, Button } from "@trashtrack/ui";
import { OperatorContext } from "@trashtrack/ui";
import { useContext } from "react";
import { useHistory } from "react-router-dom";

export function OperatorDashboard() {
const history = useHistory();
const operator = useContext(OperatorContext);

return (
<IonPage>
Expand All @@ -13,6 +16,12 @@ export function OperatorDashboard() {
<p className="text-xs text-left text-slate-600">Dashboard</p>
</div>
<div className="flex flex-col pt-8 gap-4">
<Card className="flex flex-col mt-8">
<CardContent className="pt-6">
<p className="text-sm text-slate-700">Operator Login: {operator.operator}</p>
<p className="text-sm text-slate-700">Operator Role: {operator.role}</p>
</CardContent>
</Card>
<Card className="flex flex-col mt-8">
<CardContent className="pt-6">
<Button
Expand Down
3 changes: 3 additions & 0 deletions libs/components/src/api/operator-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ import { createContext } from "react";

export const OperatorContext = createContext({
operator: null,
role: null,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
setOperator: (operator: any) => {},
// eslint-disable-next-line @typescript-eslint/no-explicit-any
setRole: (role: any) => {},
});
44 changes: 34 additions & 10 deletions libs/components/src/forms/operator/auth/login-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { z } from "zod";
import { Button } from "../../../ui/button";
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from "../../../ui/form";
import { Input } from "../../../ui/input";
import { useMutation } from "@tanstack/react-query";
import { useMutation, useQuery } from "@tanstack/react-query";
import { API_URL } from "@trashtrack/utils";

import {
Expand Down Expand Up @@ -54,7 +54,7 @@ const formSchema = z.object({

export function LoginForm() {
const history = useHistory();
const { setOperator } = useContext(OperatorContext);
const { setOperator, setRole } = useContext(OperatorContext);
const [isOpen, setIsOpen] = useState(false);
const { t } = useTranslation();

Expand All @@ -66,7 +66,13 @@ export function LoginForm() {
},
});

const { mutateAsync } = useMutation({
const { data, refetch } = useQuery({
queryKey: ["getUserDataLoginForm"],
queryFn: () => fetch(API_URL + `/user/username/${form.getValues("username")}`).then((res) => res.json()),
enabled: false,
});

const { mutateAsync, isPending } = useMutation({
mutationKey: ["comparePassword"],
mutationFn: (values: { username: string; password: string }) => {
return fetch(API_URL + `/user/compare-password/${values.username}`, {
Expand All @@ -78,17 +84,20 @@ export function LoginForm() {
body: JSON.stringify({ password: values.password }),
}).then((res) => res.json());
},
onSuccess: (data) => {
if (data.data === true) {
onSuccess: (dataMutation) => {
if (dataMutation.data === true) {
setOperator(form.getValues("username"));
history.push("/operator/tabs/dashboard");
setRole(data.data.role);

history.replace("/operator/tabs/dashboard");
} else {
setIsOpen(true);
}
},
});

async function onSubmit(values: z.infer<typeof formSchema>) {
refetch();
await mutateAsync({
username: values.username,
password: values.password,
Expand All @@ -105,7 +114,12 @@ export function LoginForm() {
<FormItem>
<FormLabel>Username</FormLabel>
<FormControl>
<Input type="text" placeholder="totallynotaopeator123" {...field} />
<Input
disabled={isPending}
type="text"
placeholder="totallynotaopeator123"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
Expand All @@ -118,18 +132,28 @@ export function LoginForm() {
<FormItem>
<FormLabel>Password</FormLabel>
<FormControl>
<Input type="password" placeholder="totallynotapassword123" {...field} />
<Input
disabled={isPending}
type="password"
placeholder="totallynotapassword123"
{...field}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>

<div className="flex flex-col gap-4">
<Button className="w-full" type="submit">
<Button className="w-full" type="submit" disabled={isPending}>
{t("operator.form.login.submit")}
</Button>
<Button className="w-full" variant="secondary" onClick={() => history.replace("/tabs/home")}>
<Button
className="w-full"
variant="secondary"
onClick={() => history.replace("/tabs/home")}
disabled={isPending}
>
{t("operator.form.login.back")}
</Button>
</div>
Expand Down

0 comments on commit 7404d1d

Please sign in to comment.