Skip to content

Commit

Permalink
Merge develop to main (#40)
Browse files Browse the repository at this point in the history
* feat: final (#34)

* fix: fixx

* feat: final

* fix: update profile bug (#36)

* fix: verify token for verify email and forgot password (#38)

* fix: fin (#39)

* fix: conflict (#41)

* Update main.yml

* Update package.json

* Update axios.ts

* feat: final (#34) (#35)

* fix: fixx

* feat: final

Co-authored-by: SansanSaga <154500077+SansanSaga@users.noreply.github.com>

* Merge develop to main (#37)

* feat: final (#34)

* fix: fixx

* feat: final

* fix: update profile bug (#36)

---------

Co-authored-by: SansanSaga <154500077+SansanSaga@users.noreply.github.com>
Co-authored-by: Laila Yunita <161436964+lailayunita@users.noreply.github.com>

---------

Co-authored-by: Daniel Reinhard <119338658+danielreinhard1129@users.noreply.github.com>
Co-authored-by: Laila Yunita <161436964+lailayunita@users.noreply.github.com>

* fix: fixing (#42)

---------

Co-authored-by: SansanSaga <154500077+SansanSaga@users.noreply.github.com>
Co-authored-by: Laila Yunita <161436964+lailayunita@users.noreply.github.com>
Co-authored-by: Samboga <samboga.ngusman@gmail.com>
  • Loading branch information
4 people authored Oct 14, 2024
1 parent d2bb53c commit c9bb67d
Show file tree
Hide file tree
Showing 21 changed files with 600 additions and 365 deletions.
4 changes: 3 additions & 1 deletion apps/api/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ config({ path: resolve(__dirname, `../${envFile}`) });
export const PORT = process.env.PORT || 8000;
export const DATABASE_URL = process.env.DATABASE_URL || '';
export const JWT_SECRET = process.env.JWT_SECRET;
export const JWT_SECRET_PASSWORD = process.env.JWT_SECRET_PASSWORD;
export const JWT_SECRET_EMAIL = process.env.JWT_SECRET_EMAIL;
export const BASE_URL_FE = process.env.BASE_URL_FE;
export const GMAIL_EMAIL = process.env.GMAIL_EMAIL;
export const GMAIL_APP_PASSWORD = process.env.GMAIL_APP_PASSWORD;
Expand All @@ -20,4 +22,4 @@ export const CLOUDINARY_API_SECRET = process.env.CLOUDINARY_API_SECRET;
export const CLOUDINARY_CLOUD_NAME = process.env.CLOUDINARY_CLOUD_NAME;
export const MIDTRANS_MERCHANT_ID = process.env.MIDTRANS_MERCHANT_ID;
export const MIDTRANS_CLIENT_KEY = process.env.MIDTRANS_CLIENT_KEY;
export const MIDTRANS_SERVER_KEY = process.env.MIDTRANS_SERVER_KEY;
export const MIDTRANS_SERVER_KEY = process.env.MIDTRANS_SERVER_KEY;
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { JWT_SECRET } from '@/config';
import { JWT_SECRET, JWT_SECRET_EMAIL } from '@/config';
import { NextFunction, Request, Response } from 'express';
import { TokenExpiredError, verify } from 'jsonwebtoken';

Expand All @@ -19,7 +19,7 @@ export const getEmailFromToken = (
});
}

verify(token, JWT_SECRET!, (err, payload) => {
verify(token, JWT_SECRET_EMAIL!, (err, payload) => {
if (err) {
if (err instanceof TokenExpiredError) {
return res.status(403).send({ message: 'token expired' });
Expand Down
37 changes: 37 additions & 0 deletions apps/api/src/lib/verifyTokenForgotPassword.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { JWT_SECRET_EMAIL, JWT_SECRET_PASSWORD } from '@/config';
import { Role } from '@prisma/client';
import { NextFunction, Request, Response } from 'express';
import { TokenExpiredError, verify } from 'jsonwebtoken';

interface PayloadToken {
id: number;
role: Role;
}

export const verifyTokenForgotPassword = (
req: Request,
res: Response,
next: NextFunction,
) => {
const token = req.headers.authorization?.split(' ')[1];

if (!token) {
return res.status(401).send({
message: 'token is missing',
});
}

verify(token, JWT_SECRET_PASSWORD!, (err, payload) => {
if (err) {
if (err instanceof TokenExpiredError) {
return res.status(403).send({ message: 'token expired' });
} else {
return res.status(401).send({ message: 'unauthorized' });
}
}

res.locals.user = payload as PayloadToken;

next();
});
};
6 changes: 3 additions & 3 deletions apps/api/src/routers/auth.router.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AuthController } from '@/controllers/auth.controller';
import { getEmailFromToken } from '@/lib/getEmailFromToken';
import { verifyToken } from '@/lib/verifyToken';
import { getEmailFromToken } from '@/lib/VerifyTokenEmail';
import { verifyTokenForgotPassword } from '@/lib/verifyTokenForgotPassword';
import {
validateCompleteRegistration,
validateEmail,
Expand Down Expand Up @@ -44,7 +44,7 @@ export class AuthRouter {
);
this.router.patch(
'/reset-password',
verifyToken,
verifyTokenForgotPassword,
validateResetPassword,
this.authController.resetPassword,
);
Expand Down
7 changes: 4 additions & 3 deletions apps/api/src/services/auth/forgot-password.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BASE_URL_FE, JWT_SECRET } from '@/config';
import { BASE_URL_FE, JWT_SECRET_PASSWORD } from '@/config';
import { transporter } from '@/lib/nodemailer';
import prisma from '@/prisma';
import { sign } from 'jsonwebtoken';
Expand All @@ -16,7 +16,7 @@ export const forgotPasswordService = async (email: string) => {
throw new Error('Invalid email address');
}

const token = sign({ id: user.id }, JWT_SECRET!, {
const token = sign({ id: user.id }, JWT_SECRET_PASSWORD!, {
expiresIn: '30m',
});

Expand Down Expand Up @@ -50,7 +50,8 @@ export const forgotPasswordService = async (email: string) => {
});

return {
message: 'Send email success',
message: 'Update profile success',
token,
};
} catch (error) {
throw error;
Expand Down
5 changes: 3 additions & 2 deletions apps/api/src/services/auth/register.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { BASE_URL_FE, JWT_SECRET } from '@/config';
import { BASE_URL_FE, JWT_SECRET, JWT_SECRET_EMAIL } from '@/config';
import { transporter } from '@/lib/nodemailer';
import prisma from '@/prisma';
import { User } from '@prisma/client';
Expand Down Expand Up @@ -28,7 +28,7 @@ export const registerService = async (body: User) => {
},
});

const token = sign({ email }, JWT_SECRET!, {
const token = sign({ email }, JWT_SECRET_EMAIL!, {
expiresIn: '60m',
});

Expand Down Expand Up @@ -73,6 +73,7 @@ export const registerService = async (body: User) => {
return {
newUser,
message: 'Register Success',
token,
};
});
} catch (error) {
Expand Down
1 change: 1 addition & 0 deletions apps/web/src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ export const Header = () => {
<Link href="/orders">My Orders</Link>
<Link href="/pickup-orders">Pickup Orders</Link>
<Link href="/delivery-orders">Delivery Orders</Link>
<Link href="/notifications">Notifications</Link>

<hr />
</div>
Expand Down
41 changes: 41 additions & 0 deletions apps/web/src/components/TableSkeletonPure.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Skeleton } from "@/components/ui/skeleton";
import { Button } from "@/components/ui/button";
import Link from "next/link";
import { FaPlus } from "react-icons/fa";

const TableSkeletonPure = () => {
return (
<div className="mx-auto max-w-7xl space-y-8 p-6 md:p-10">
<div className="flex items-center justify-between">
<h3 className="text-2xl font-semibold">
<Skeleton className="h-6 w-32" />
</h3>
</div>

<section className="rounded-md border-[1px] bg-white">
<Skeleton className="h-12 w-full border-b-[1px]" />
<div className="space-y-2">
{[...Array(3)].map((_, index) => (
<div key={index} className="flex items-center justify-between p-2">
<Skeleton className="h-5 w-12" />
<Skeleton className="h-5 w-32" />
<Skeleton className="h-5 w-24" />
<Skeleton className="h-5 w-24" />
<Skeleton className="h-5 w-24" />
<div className="flex gap-2">
<Skeleton className="h-8 w-12" />
<Skeleton className="h-8 w-12" />
</div>
</div>
))}
</div>
</section>

<div className="flex justify-center">
<Skeleton className="h-10 w-48" />
</div>
</div>
);
};

export default TableSkeletonPure;
11 changes: 8 additions & 3 deletions apps/web/src/features/dashboard/delivery-orders/admins/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ const DashboardDeliveryOrdersAdminsPage = () => {
page: String(searchParams.page),
}).toString();

router.push(`/dashboard/orders?${query}`);
router.push(`/dashboard/delivery-orders?${query}`);
refetch();
}, [searchParams]);

Expand All @@ -107,10 +107,15 @@ const DashboardDeliveryOrdersAdminsPage = () => {
return (
<>
<DashboardHeader />
<div className="text-md md: mx-auto h-full bg-white p-4">
<div className="px-6">
<div className="flex h-16 items-center justify-between rounded-md bg-[#e5f3f6] p-4 shadow">
<h3 className="text-xl font-semibold text-[#37bae3]">Delivery Orders</h3>
</div>
</div>
<div className="text-md md: mx-auto h-full bg-white p-6">
<Card className="shadow-sm">
<CardHeader>
<CardTitle className="text-xl">Delivery orders</CardTitle>
<CardTitle className="text-xl">List of delivery orders</CardTitle>
<CardDescription>List of delivery orders</CardDescription>
</CardHeader>
<CardContent>
Expand Down
17 changes: 13 additions & 4 deletions apps/web/src/features/dashboard/delivery-orders/drivers/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { useRouter, useSearchParams } from "next/navigation";
import DeliveryOrderCard from "../components/DeliveryOrderCard";

const DashboardDeliveryOrdersDriversPage = () => {
const router = useRouter()
const router = useRouter();
const [searchValue, setSearchValue] = useState("");
const [debouncedSearch] = useDebounceValue(searchValue, 500);
const isDesktop = useMediaQuery("(min-width: 768px)", {
Expand All @@ -43,7 +43,9 @@ const DashboardDeliveryOrdersDriversPage = () => {
sortBy: queryParams.get("sortBy") || "createdAt",
sortOrder: (queryParams.get("sortOrder") as "asc" | "desc") || "desc",
search: queryParams.get("search") || "",
status: (queryParams.get("status") as "ONGOING" | "REQUEST" | "HISTORY") || "REQUEST",
status:
(queryParams.get("status") as "ONGOING" | "REQUEST" | "HISTORY") ||
"REQUEST",
});

const { data, isPending, refetch } = useGetDeliveryOrdersDrivers({
Expand Down Expand Up @@ -92,10 +94,17 @@ const DashboardDeliveryOrdersDriversPage = () => {
return (
<>
<DashboardHeader />
<div className="text-md md: mx-auto h-full bg-white p-4">
<div className="px-6">
<div className="flex h-16 items-center justify-between rounded-md bg-[#e5f3f6] p-4 shadow">
<h3 className="text-xl font-semibold text-[#37bae3]">
Delivery Orders
</h3>
</div>
</div>
<div className="text-md md: mx-auto h-full bg-white p-6">
<Card className="shadow-sm">
<CardHeader>
<CardTitle className="text-xl">Delivery Orders</CardTitle>
<CardTitle className="text-xl">List of delivery Orders</CardTitle>
<CardDescription>List of delivery orders</CardDescription>
</CardHeader>
<CardContent>
Expand Down
33 changes: 28 additions & 5 deletions apps/web/src/features/dashboard/earnings/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { getDaysInMonth } from "date-fns";
import { useSession } from "next-auth/react";
import { useState } from "react";
import ChartEvents from "./components/ChartEvents";
import { Loader2 } from "lucide-react";

ChartJS.register(
LineElement,
Expand Down Expand Up @@ -85,6 +86,21 @@ const DashboardEarningsPage = () => {
}
};

const months = [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
];

if (!session.data) {
return <DashboardHeader />;
}
Expand All @@ -97,20 +113,27 @@ const DashboardEarningsPage = () => {
return (
<>
<DashboardHeader />
<Loader2 className="mx-auto" />
</>
);
}
if (data) {
return (
<>
<DashboardHeader />
<div className="text-md md: mx-auto h-full px-6">
<div className="px-6">
<div className="flex h-16 items-center justify-between rounded-md bg-[#e5f3f6] p-4 shadow">
<h3 className="text-xl font-semibold text-[#37bae3]">Earnings</h3>
</div>
</div>
<div className="text-md md: mx-auto h-full p-6">
<Card className="shadow-sm">
<CardHeader>
<CardTitle className="text-xl">Earnings</CardTitle>
<CardTitle className="text-xl">
{months[Number(filterMonth) - 1]}
</CardTitle>
<CardDescription className="flex justify-between">
<div>Earning data</div>
<div>All time total: {result.format(data.totalIncome)}</div>
<div>Total: {result.format(data.totalIncome)}</div>
</CardDescription>
</CardHeader>
<CardContent>
Expand All @@ -120,7 +143,7 @@ const DashboardEarningsPage = () => {
<Select
name="month"
onValueChange={handleChangeFilterMonth}
defaultValue={`${now.getMonth() + 1}`}
defaultValue={filterMonth}
>
<SelectTrigger className="min-w-40">
<SelectValue placeholder="Month" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Badge } from "@/components/ui/badge";
import { Card } from "@/components/ui/card";
import { format } from "date-fns";

interface NotificationCardProps {
title: string;
message: string;
timeOfOrder: Date;
}

const NotificationCard: React.FC<NotificationCardProps> = ({
title,
message,
timeOfOrder,
}) => {
const createdAt = format(new Date(timeOfOrder), "dd MMM yyyy, HH:mm:ss");

return (
<Card>
<div className="flex flex-row items-center justify-between bg-[#e5f3f6] p-4">
<span className="font-semibold">{createdAt}</span>
<Badge>Notifikasi</Badge>
</div>
<div className="space-y-2 p-4">
<div className="rounded-md bg-neutral-100 p-2 text-center">{title}</div>
<div className="flex flex-col gap-2">
<p className="line-clamp-4">{message}</p>
</div>
</div>
</Card>
);
};

export default NotificationCard;
Loading

0 comments on commit c9bb67d

Please sign in to comment.