Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions frontend/components/BookButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from "react";

type BookButtonProps = {
label: string;
icon?: React.ReactNode;
onClick?: () => void;
size?: "sm" | "md" | "lg";
};

function BookButton({ label, icon, onClick, size = "md"}: BookButtonProps) {

const sizes = {
sm: "px-4 py-2 text-sm",
md: "px-5 py-2.5 text-sm",
lg: "px-7 py-4 text-base",
};

return (
<button
onClick={onClick}
className={`
cursor-pointer
inline-flex
items-center
gap-2
rounded-full
bg-[rgb(117,13,234)]
font-medium
text-white
shadow-[inset_0_1px_0_rgba(255,255,255,0.12),0_8px_24px_rgba(117,13,234,0.35)]
transition-all
hover:shadow-[inset_0_1px_0_rgba(255,255,255,0.15),0_10px_30px_rgba(117,13,234,0.45)]
hover:scale-[1.02]
active:scale-[0.98]
${sizes[size]}
`}
>
<span>{label}</span>

{icon && (
<span className="flex items-center">
{icon}
</span>
)}
</button>
);
}

export default BookButton;
102 changes: 102 additions & 0 deletions frontend/components/CountDown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
"use client";

import React, { useEffect, useState } from "react";

type TimeLeft = {
days: number;
hours: number;
minutes: number;
seconds: number;
};

type CountdownProps = {
targetDate: Date;
};

function Countdown({ targetDate }: CountdownProps) {
const calculateTimeLeft = (): TimeLeft => {
const difference = +targetDate - +new Date();

let timeLeft: TimeLeft = {
days: 0,
hours: 0,
minutes: 0,
seconds: 0,
};

if (difference > 0) {
timeLeft = {
days: Math.floor(difference / (1000 * 60 * 60 * 24)),
hours: Math.floor((difference / (1000 * 60 * 60)) % 24),
minutes: Math.floor((difference / 1000 / 60) % 60),
seconds: Math.floor((difference / 1000) % 60),
};
}

return timeLeft;
};

const [timeLeft, setTimeLeft] = useState<TimeLeft>(calculateTimeLeft());

useEffect(() => {
const timer = setInterval(() => {
setTimeLeft(calculateTimeLeft());
}, 1000);

return () => clearInterval(timer);
}, []);

const format = (num: number) => String(num).padStart(2, "0");

return (
<div className="mb-5 flex justify-center gap-1.5">
{/* Days */}
<div className="w-9 rounded-md bg-primary px-0 pb-1 pt-2 text-center text-white">
<div className="font-mono text-base font-bold leading-none">
{format(timeLeft.days)}
</div>
<div className="text-[8px] uppercase tracking-[0.1em] opacity-85">
D
</div>
</div>

<div className="flex items-center text-base font-bold text-accent">:</div>

{/* Hours */}
<div className="w-9 rounded-md bg-primary px-0 pb-1 pt-2 text-center text-white">
<div className="font-mono text-base font-bold leading-none">
{format(timeLeft.hours)}
</div>
<div className="text-[8px] uppercase tracking-[0.1em] opacity-85">
H
</div>
</div>

<div className="flex items-center text-base font-bold text-accent">:</div>

{/* Minutes */}
<div className="w-9 rounded-md bg-primary px-0 pb-1 pt-2 text-center text-white">
<div className="font-mono text-base font-bold leading-none">
{format(timeLeft.minutes)}
</div>
<div className="text-[8px] uppercase tracking-[0.1em] opacity-85">
M
</div>
</div>

<div className="flex items-center text-base font-bold text-accent">:</div>

{/* Seconds */}
<div className="w-9 rounded-md bg-primary px-0 pb-1 pt-2 text-center text-white">
<div className="font-mono text-base font-bold leading-none">
{format(timeLeft.seconds)}
</div>
<div className="text-[8px] uppercase tracking-[0.1em] opacity-85">
S
</div>
</div>
</div>
);
}

export default Countdown;
15 changes: 9 additions & 6 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,22 @@
"lint": "next lint"
},
"dependencies": {
"bootstrap": "^5.3.8",
"lucide": "^1.3.0",
"lucide-react": "^1.3.0",
"next": "15.2.4",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"next": "15.2.4"
"react-dom": "^19.0.0"
},
"devDependencies": {
"typescript": "^5",
"@eslint/eslintrc": "^3",
"@tailwindcss/postcss": "^4",
"@types/node": "^20",
"@types/react": "^19",
"@types/react-dom": "^19",
"@tailwindcss/postcss": "^4",
"tailwindcss": "^4",
"eslint": "^9",
"eslint-config-next": "15.2.4",
"@eslint/eslintrc": "^3"
"tailwindcss": "^4",
"typescript": "^5"
}
}
Loading