Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
ed0ed20
feat: improve seo and add pwa support
diogogmatos Sep 8, 2025
687b627
chore: format
diogogmatos Sep 8, 2025
e1a4022
feat: move metadata to layouts
diogogmatos Sep 8, 2025
d14b3bc
feat: add an install prompt
diogogmatos Sep 8, 2025
15b2469
fix: close prompt after install
diogogmatos Sep 8, 2025
f3fefe6
chore: reduce clutter by moving simple metadata to html tags
diogogmatos Sep 9, 2025
b33fe35
Merge branch 'main' into dm/seo+pwa
diogogmatos Sep 9, 2025
d33c846
Merge branch 'main' into dm/seo+pwa
diogogmatos Sep 12, 2025
8589d3f
feat: add og image
diogogmatos Sep 12, 2025
72ecf39
Merge branch 'main' into dm/seo+pwa
diogogmatos Sep 12, 2025
758dd48
feat: add screenshots to android install prompt
diogogmatos Sep 12, 2025
a9de71b
Merge branch 'main' into dm/seo+pwa
diogogmatos Sep 15, 2025
93010a4
chore: update hrefs
diogogmatos Sep 15, 2025
3cb1131
chore: change domain
diogogmatos Sep 15, 2025
8897d31
chore: rollback route renames
diogogmatos Sep 15, 2025
ddaf0ca
chore: update screenshots
diogogmatos Sep 15, 2025
15762ee
chore: remove 'use-client'
diogogmatos Sep 15, 2025
68b761d
feat: add shortcut icons
diogogmatos Sep 16, 2025
f63e70d
feat: add 'Install' button
diogogmatos Sep 16, 2025
e5b6533
feat: add prompt dismissal limit
diogogmatos Sep 16, 2025
ee7fbeb
chore: simplify page titles
diogogmatos Sep 16, 2025
4dcf5e5
fix: fuckup
diogogmatos Sep 16, 2025
ac10bfc
chore: reduce prompt limit to 2
diogogmatos Sep 16, 2025
d8d1892
Merge branch 'main' into dm/seo+pwa
diogogmatos Sep 22, 2025
772e695
chore: remove auto-popup feat
diogogmatos Sep 22, 2025
d7b25bb
fix: move app url to env var
diogogmatos Sep 27, 2025
d14ffc2
fix: remove console log and css typo
diogogmatos Sep 27, 2025
f3b1594
chore: replace urls with var, add var to env sample
diogogmatos Sep 27, 2025
3f24ded
fix: screenshot image paths
diogogmatos Sep 27, 2025
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
1 change: 1 addition & 0 deletions .env.sample
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
NEXT_PUBLIC_API_URL=http://localhost:4000/v1
UMAMI_URL=<your-umami-url>
UMAMI_WEBSITE_ID=<your-umami-website-id>
PROD_DOMAIN=<your-production-domain>
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,5 @@ next-env.d.ts

*storybook.log
storybook-static

certificates
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/exchange-512x512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/favicon-16x16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/favicon-32x32.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/favicon-48x48.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/favicon-64x64.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/favicon-96x96.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/ios/100.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/ios/1024.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/ios/114.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/ios/120.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/ios/128.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/ios/144.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/ios/152.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/ios/16.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/ios/167.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/ios/180.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/ios/192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/ios/20.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/ios/256.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added public/icons/ios/29.png
Binary file added public/icons/ios/32.png
Binary file added public/icons/ios/40.png
Binary file added public/icons/ios/50.png
Binary file added public/icons/ios/512.png
Binary file added public/icons/ios/57.png
Binary file added public/icons/ios/58.png
Binary file added public/icons/ios/60.png
Binary file added public/icons/ios/64.png
Binary file added public/icons/ios/72.png
Binary file added public/icons/ios/76.png
Binary file added public/icons/ios/80.png
Binary file added public/icons/ios/87.png
Binary file added public/icons/schedule-512x512.png
Binary file added public/icons/windows11/LargeTile.scale-100.png
Binary file added public/icons/windows11/LargeTile.scale-125.png
Binary file added public/icons/windows11/LargeTile.scale-150.png
Binary file added public/icons/windows11/LargeTile.scale-200.png
Binary file added public/icons/windows11/LargeTile.scale-400.png
Binary file added public/icons/windows11/SmallTile.scale-100.png
Binary file added public/icons/windows11/SmallTile.scale-125.png
Binary file added public/icons/windows11/SmallTile.scale-150.png
Binary file added public/icons/windows11/SmallTile.scale-200.png
Binary file added public/icons/windows11/SmallTile.scale-400.png
Binary file added public/icons/windows11/SplashScreen.scale-100.png
Binary file added public/icons/windows11/SplashScreen.scale-150.png
Binary file added public/icons/windows11/SplashScreen.scale-200.png
Binary file added public/icons/windows11/SplashScreen.scale-400.png
Binary file added public/icons/windows11/Square44x44Logo.scale-100.png
Binary file added public/icons/windows11/StoreLogo.scale-100.png
Binary file added public/icons/windows11/StoreLogo.scale-125.png
Binary file added public/icons/windows11/StoreLogo.scale-150.png
Binary file added public/icons/windows11/StoreLogo.scale-200.png
Binary file added public/icons/windows11/StoreLogo.scale-400.png
Binary file added public/images/og.png
Binary file added public/images/screenshots/1.png
Binary file added public/images/screenshots/2.png
Binary file added public/images/screenshots/3.png
Binary file added public/images/screenshots/4.png
Binary file added public/images/screenshots/5.png
Binary file added public/images/screenshots/6.png
48 changes: 48 additions & 0 deletions src/app/(app)/exchange/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Metadata } from "next";

export const metadata: Metadata = {
title: "Exchange | Pombo",
description:
"Don't like your schedule? Easily swap classes with other students",
openGraph: {
url: "/exchange",
type: "website",
title: "Exchange | Pombo",
description:
"Don't like your schedule? Easily swap classes with other students",
images: [
{
url: "/images/og.png",
width: 1200,
height: 630,
alt: process.env.PROD_DOMAIN,
},
],
},
twitter: {
card: "summary_large_image",
title: "Exchange | Pombo",
description:
"Don't like your schedule? Easily swap classes with other students",
images: [
{
url: "/images/og.png",
width: 1200,
height: 630,
alt: process.env.PROD_DOMAIN,
},
],
},
robots: {
index: false,
follow: false,
},
};

export default function ExchangeLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return children;
}
5 changes: 0 additions & 5 deletions src/app/(app)/exchange/page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import MainSection from "@/components/exchange/main-section";
import SideSection from "@/components/exchange/side-section";
import { AuthCheck } from "@/components/auth-check";
import { Metadata } from "next";

export const metadata: Metadata = {
title: "Pombo | Exchange",
};

export default function Exchange() {
return (
Expand Down
52 changes: 46 additions & 6 deletions src/app/(app)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,43 @@
import { Metadata } from "next";
import { AuthCheck } from "@/components/auth-check";
import Navbar from "@/components/navbar";
import { InstallPromptProvider } from "@/contexts/install-prompt-provider";

export const metadata: Metadata = {
title: "Calendar | Pombo",
description: "Keep track of your calendar and don't miss a single deadline",
openGraph: {
url: "/",
type: "website",
title: "Calendar | Pombo",
description: "Keep track of your calendar and don't miss a single deadline",
images: [
{
url: "/images/og.png",
width: 1200,
height: 630,
alt: process.env.PROD_DOMAIN,
},
],
},
twitter: {
card: "summary_large_image",
title: "Calendar | Pombo",
description: "Keep track of your calendar and don't miss a single deadline",
images: [
{
url: "/images/og.png",
width: 1200,
height: 630,
alt: process.env.PROD_DOMAIN,
},
],
},
robots: {
index: false,
follow: false,
},
};

export default function AppLayout({
children,
Expand All @@ -8,12 +46,14 @@ export default function AppLayout({
}>) {
return (
<AuthCheck shouldBeLoggedIn>
<div className="flex h-dvh flex-col">
<Navbar />
<main className="min-h-0 flex-1 px-5 pt-3.5 pb-7.5 antialiased md:px-7.5">
{children}
</main>
</div>
<InstallPromptProvider>
<div className="flex h-dvh flex-col">
<Navbar />
<main className="min-h-0 flex-1 px-5 pt-3.5 pb-7.5 antialiased md:px-7.5">
{children}
</main>
</div>
</InstallPromptProvider>
</AuthCheck>
);
}
6 changes: 0 additions & 6 deletions src/app/(app)/page.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
import { Metadata } from "next";
import EventsCalendar from "@/components/events-calendar";
import CalendarOptions from "@/components/calendar-options";

export const metadata: Metadata = {
title: "Pombo | Calendar",
};

export default function Home() {
return (
<div className="flex h-full flex-col-reverse gap-5 md:flex-row md:gap-8">
<CalendarOptions />

<EventsCalendar />
</div>
);
Expand Down
45 changes: 45 additions & 0 deletions src/app/(app)/schedule/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Metadata } from "next";

export const metadata: Metadata = {
title: "Schedule | Pombo",
description: "Keep track of your timetable and don't miss a single class",
openGraph: {
url: "/schedule",
type: "website",
title: "Schedule | Pombo",
description: "Keep track of your timetable and don't miss a single class",
images: [
{
url: "/images/og.png",
width: 1200,
height: 630,
alt: process.env.PROD_DOMAIN,
},
],
},
twitter: {
card: "summary_large_image",
title: "Schedule | Pombo",
description: "Keep track of your timetable and don't miss a single class",
images: [
{
url: "/images/og.png",
width: 1200,
height: 630,
alt: process.env.PROD_DOMAIN,
},
],
},
robots: {
index: false,
follow: false,
},
};

export default function ScheduleLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return children;
}
6 changes: 0 additions & 6 deletions src/app/(app)/schedule/page.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
import { Metadata } from "next";
import ScheduleCalendar from "@/components/schedule-calendar";

import { ScheduleProvider } from "@/contexts/schedule-provider";
import CalendarOptions from "@/components/calendar-options";
import { AuthCheck } from "@/components/auth-check";

export const metadata: Metadata = {
title: "Pombo | Schedule",
};

export default function Schedule() {
return (
<AuthCheck userTypes={["student"]}>
Expand Down
157 changes: 81 additions & 76 deletions src/app/(app)/settings/account/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,87 +102,92 @@ export default function Account() {
const changePassword = useChangePassword();

return (
<SettingsWrapper title="Account and profile">
<div className="flex flex-col items-center md:items-start">
<title>Pombo | Account</title>

<div className="w-full max-w-md space-y-5 md:max-w-none md:space-y-10">
<section className="flex items-center justify-center gap-5 md:items-start md:justify-start md:gap-7.5">
<Avatar
name={user.data?.name}
className="size-25 md:size-30 lg:size-35"
/>
<div className="space-y-1 md:pt-3.5">
<h2 className="text-dark text-xl font-semibold sm:text-2xl lg:text-3xl">
{firstLastName(user.data?.name)}
</h2>
<p className="text-sm font-semibold md:text-base">
{user.data?.email}
</p>
</div>
</section>

<section className="flex flex-col items-center gap-3.5 md:items-start">
<h2 className="text-xl font-semibold md:text-2xl">Information</h2>
<div className="flex w-full max-w-3xl flex-col gap-1.5">
<InputLine
disabled
label="Full Name"
value={user.data?.name || "user name"}
<>
<title>Account | Pombo</title>
<SettingsWrapper title="Account and profile">
<div className="flex flex-col items-center md:items-start">
<div className="w-full max-w-md space-y-5 md:max-w-none md:space-y-10">
<section className="flex items-center justify-center gap-5 md:items-start md:justify-start md:gap-7.5">
<Avatar
name={user.data?.name}
className="size-25 md:size-30 lg:size-35"
/>
<InputLine
disabled
label="Email"
value={user.data?.email || "user email"}
/>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-1.5">
<InputLine
id="current_password"
type="password"
className="mt-6"
label="Current password"
value={"current_password"}
placeholder="Current password"
{...register("current_password", { required: true })}
errorMessage={errors.current_password?.message}
/>
<div className="space-y-1 md:pt-3.5">
<h2 className="text-dark text-xl font-semibold sm:text-2xl lg:text-3xl">
{firstLastName(user.data?.name)}
</h2>
<p className="text-sm font-semibold md:text-base">
{user.data?.email}
</p>
</div>
</section>

<section className="flex flex-col items-center gap-3.5 md:items-start">
<h2 className="text-xl font-semibold md:text-2xl">Information</h2>
<div className="flex w-full max-w-3xl flex-col gap-1.5">
<InputLine
id="password"
type="password"
label="New password"
value={"password"}
placeholder="New password"
{...register("password", { required: true })}
errorMessage={errors.password?.message}
disabled
label="Full Name"
value={user.data?.name || "user name"}
/>
<InputLine
id="password_confirmation"
type="password"
label="Confirm password"
value={"password_confirmation"}
placeholder="Confirm password"
{...register("password_confirmation", { required: true })}
errorMessage={errors.password_confirmation?.message}
disabled
label="Email"
value={user.data?.email || "user email"}
/>
<button
type="submit"
className="bg-primary-400 hover:bg-primary-400/95 mt-6 cursor-pointer rounded-lg px-4 py-2 font-semibold text-white transition-all duration-200 hover:scale-98 md:w-1/3"
>
Change Password
</button>

{changePassword.isSuccess && (
<p className="text-dark/50">Password Changed Successfully</p>
)}

{changePassword.isError && (
<p className="text-dark/50">{changePassword.error.message}</p>
)}
</form>
</div>
</section>
<form onSubmit={handleSubmit(onSubmit)} className="space-y-1.5">
<InputLine
id="current_password"
type="password"
className="mt-6"
label="Current password"
value={"current_password"}
placeholder="Current password"
{...register("current_password", { required: true })}
errorMessage={errors.current_password?.message}
/>
<InputLine
id="password"
type="password"
label="New password"
value={"password"}
placeholder="New password"
{...register("password", { required: true })}
errorMessage={errors.password?.message}
/>
<InputLine
id="password_confirmation"
type="password"
label="Confirm password"
value={"password_confirmation"}
placeholder="Confirm password"
{...register("password_confirmation", { required: true })}
errorMessage={errors.password_confirmation?.message}
/>
<button
type="submit"
className="bg-primary-400 hover:bg-primary-400/95 mt-6 cursor-pointer rounded-lg px-4 py-2 font-semibold text-white transition-all duration-200 hover:scale-98 md:w-1/3"
>
Change Password
</button>

{changePassword.isSuccess && (
<p className="text-dark/50">
Password Changed Successfully
</p>
)}

{changePassword.isError && (
<p className="text-dark/50">
{changePassword.error.message}
</p>
)}
</form>
</div>
</section>
</div>
</div>
</div>
</SettingsWrapper>
</SettingsWrapper>
</>
);
}
Loading