From b9f73e9a90bdc11c8d8f90aae6a81de6ff77b085 Mon Sep 17 00:00:00 2001 From: Knee Cola Date: Tue, 25 Nov 2025 21:49:01 +0100 Subject: [PATCH] Restructure application to use /home for authenticated pages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move authenticated home page from /[locale] to /[locale]/home - Move login page from /[locale]/login to /[locale] (new landing page) - Move all restricted pages (bill, location, year-month, print, account) under /[locale]/home - Simplify middleware to protect all routes under /home instead of using publicPages array - Update auth config: change signIn page from /login to / - Update SignInButton callback URL to redirect to /home after login - Update all internal links throughout the application to reflect new structure - Update server action redirects in navigationActions.ts - Public share routes (/share/*) remain unchanged 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .claude/settings.local.json | 3 +- .../{ => home}/account/LogoutButton.tsx | 0 app/[locale]/{ => home}/account/page.tsx | 2 +- .../{ => home}/account/settings/page.tsx | 0 .../{ => home}/bill/[id]/add/not-found.tsx | 0 .../{ => home}/bill/[id]/add/page.tsx | 0 .../{ => home}/bill/[id]/delete/not-found.tsx | 0 .../{ => home}/bill/[id]/delete/page.tsx | 0 .../{ => home}/bill/[id]/edit/not-found.tsx | 0 .../{ => home}/bill/[id]/edit/page.tsx | 0 .../location/[id]/add/LocationAddPage.tsx | 0 .../{ => home}/location/[id]/add/page.tsx | 0 .../[id]/delete/LocationDeletePage.tsx | 0 .../location/[id]/delete/not-found.tsx | 0 .../{ => home}/location/[id]/delete/page.tsx | 0 .../location/[id]/edit/LocationEditPage.tsx | 0 .../location/[id]/edit/not-found.tsx | 0 .../{ => home}/location/[id]/edit/page.tsx | 0 app/[locale]/home/page.tsx | 31 +++++ .../print/[year]/[month]/not-found.tsx | 0 .../{ => home}/print/[year]/[month]/page.tsx | 0 .../{ => home}/year-month/[id]/add/page.tsx | 0 app/[locale]/login/page.tsx | 109 ----------------- app/[locale]/page.tsx | 112 +++++++++++++++--- app/lib/actions/navigationActions.ts | 6 +- app/lib/auth.ts | 2 +- app/ui/AddLocationButton.tsx | 2 +- app/ui/AddMonthButton.tsx | 2 +- app/ui/BillBadge.tsx | 2 +- app/ui/BillDeleteForm.tsx | 2 +- app/ui/BillEditForm.tsx | 2 +- app/ui/LocationCard.tsx | 4 +- app/ui/LocationDeleteForm.tsx | 2 +- app/ui/LocationEditForm.tsx | 2 +- app/ui/MonthLocationList.tsx | 4 +- app/ui/NotFoundPage.tsx | 2 +- app/ui/PageFooter.tsx | 2 +- app/ui/PageHeader.tsx | 4 +- app/ui/PrintButton.tsx | 2 +- app/ui/SignInButton.tsx | 2 +- middleware.ts | 19 ++- 41 files changed, 158 insertions(+), 160 deletions(-) rename app/[locale]/{ => home}/account/LogoutButton.tsx (100%) rename app/[locale]/{ => home}/account/page.tsx (86%) rename app/[locale]/{ => home}/account/settings/page.tsx (100%) rename app/[locale]/{ => home}/bill/[id]/add/not-found.tsx (100%) rename app/[locale]/{ => home}/bill/[id]/add/page.tsx (100%) rename app/[locale]/{ => home}/bill/[id]/delete/not-found.tsx (100%) rename app/[locale]/{ => home}/bill/[id]/delete/page.tsx (100%) rename app/[locale]/{ => home}/bill/[id]/edit/not-found.tsx (100%) rename app/[locale]/{ => home}/bill/[id]/edit/page.tsx (100%) rename app/[locale]/{ => home}/location/[id]/add/LocationAddPage.tsx (100%) rename app/[locale]/{ => home}/location/[id]/add/page.tsx (100%) rename app/[locale]/{ => home}/location/[id]/delete/LocationDeletePage.tsx (100%) rename app/[locale]/{ => home}/location/[id]/delete/not-found.tsx (100%) rename app/[locale]/{ => home}/location/[id]/delete/page.tsx (100%) rename app/[locale]/{ => home}/location/[id]/edit/LocationEditPage.tsx (100%) rename app/[locale]/{ => home}/location/[id]/edit/not-found.tsx (100%) rename app/[locale]/{ => home}/location/[id]/edit/page.tsx (100%) create mode 100644 app/[locale]/home/page.tsx rename app/[locale]/{ => home}/print/[year]/[month]/not-found.tsx (100%) rename app/[locale]/{ => home}/print/[year]/[month]/page.tsx (100%) rename app/[locale]/{ => home}/year-month/[id]/add/page.tsx (100%) delete mode 100644 app/[locale]/login/page.tsx diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 9f194ab..c2c34b7 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -11,7 +11,8 @@ "mcp__serena__replace_regex", "Bash(npm install:*)", "mcp__ide__getDiagnostics", - "mcp__serena__execute_shell_command" + "mcp__serena__execute_shell_command", + "mcp__serena__check_onboarding_performed" ] }, "enableAllProjectMcpServers": true, diff --git a/app/[locale]/account/LogoutButton.tsx b/app/[locale]/home/account/LogoutButton.tsx similarity index 100% rename from app/[locale]/account/LogoutButton.tsx rename to app/[locale]/home/account/LogoutButton.tsx diff --git a/app/[locale]/account/page.tsx b/app/[locale]/home/account/page.tsx similarity index 86% rename from app/[locale]/account/page.tsx rename to app/[locale]/home/account/page.tsx index d60ace9..b9950cc 100644 --- a/app/[locale]/account/page.tsx +++ b/app/[locale]/home/account/page.tsx @@ -16,7 +16,7 @@ const Page: FC = async () => {

{t('title')}

- {t('settings-button')} + {t('settings-button')}
diff --git a/app/[locale]/account/settings/page.tsx b/app/[locale]/home/account/settings/page.tsx similarity index 100% rename from app/[locale]/account/settings/page.tsx rename to app/[locale]/home/account/settings/page.tsx diff --git a/app/[locale]/bill/[id]/add/not-found.tsx b/app/[locale]/home/bill/[id]/add/not-found.tsx similarity index 100% rename from app/[locale]/bill/[id]/add/not-found.tsx rename to app/[locale]/home/bill/[id]/add/not-found.tsx diff --git a/app/[locale]/bill/[id]/add/page.tsx b/app/[locale]/home/bill/[id]/add/page.tsx similarity index 100% rename from app/[locale]/bill/[id]/add/page.tsx rename to app/[locale]/home/bill/[id]/add/page.tsx diff --git a/app/[locale]/bill/[id]/delete/not-found.tsx b/app/[locale]/home/bill/[id]/delete/not-found.tsx similarity index 100% rename from app/[locale]/bill/[id]/delete/not-found.tsx rename to app/[locale]/home/bill/[id]/delete/not-found.tsx diff --git a/app/[locale]/bill/[id]/delete/page.tsx b/app/[locale]/home/bill/[id]/delete/page.tsx similarity index 100% rename from app/[locale]/bill/[id]/delete/page.tsx rename to app/[locale]/home/bill/[id]/delete/page.tsx diff --git a/app/[locale]/bill/[id]/edit/not-found.tsx b/app/[locale]/home/bill/[id]/edit/not-found.tsx similarity index 100% rename from app/[locale]/bill/[id]/edit/not-found.tsx rename to app/[locale]/home/bill/[id]/edit/not-found.tsx diff --git a/app/[locale]/bill/[id]/edit/page.tsx b/app/[locale]/home/bill/[id]/edit/page.tsx similarity index 100% rename from app/[locale]/bill/[id]/edit/page.tsx rename to app/[locale]/home/bill/[id]/edit/page.tsx diff --git a/app/[locale]/location/[id]/add/LocationAddPage.tsx b/app/[locale]/home/location/[id]/add/LocationAddPage.tsx similarity index 100% rename from app/[locale]/location/[id]/add/LocationAddPage.tsx rename to app/[locale]/home/location/[id]/add/LocationAddPage.tsx diff --git a/app/[locale]/location/[id]/add/page.tsx b/app/[locale]/home/location/[id]/add/page.tsx similarity index 100% rename from app/[locale]/location/[id]/add/page.tsx rename to app/[locale]/home/location/[id]/add/page.tsx diff --git a/app/[locale]/location/[id]/delete/LocationDeletePage.tsx b/app/[locale]/home/location/[id]/delete/LocationDeletePage.tsx similarity index 100% rename from app/[locale]/location/[id]/delete/LocationDeletePage.tsx rename to app/[locale]/home/location/[id]/delete/LocationDeletePage.tsx diff --git a/app/[locale]/location/[id]/delete/not-found.tsx b/app/[locale]/home/location/[id]/delete/not-found.tsx similarity index 100% rename from app/[locale]/location/[id]/delete/not-found.tsx rename to app/[locale]/home/location/[id]/delete/not-found.tsx diff --git a/app/[locale]/location/[id]/delete/page.tsx b/app/[locale]/home/location/[id]/delete/page.tsx similarity index 100% rename from app/[locale]/location/[id]/delete/page.tsx rename to app/[locale]/home/location/[id]/delete/page.tsx diff --git a/app/[locale]/location/[id]/edit/LocationEditPage.tsx b/app/[locale]/home/location/[id]/edit/LocationEditPage.tsx similarity index 100% rename from app/[locale]/location/[id]/edit/LocationEditPage.tsx rename to app/[locale]/home/location/[id]/edit/LocationEditPage.tsx diff --git a/app/[locale]/location/[id]/edit/not-found.tsx b/app/[locale]/home/location/[id]/edit/not-found.tsx similarity index 100% rename from app/[locale]/location/[id]/edit/not-found.tsx rename to app/[locale]/home/location/[id]/edit/not-found.tsx diff --git a/app/[locale]/location/[id]/edit/page.tsx b/app/[locale]/home/location/[id]/edit/page.tsx similarity index 100% rename from app/[locale]/location/[id]/edit/page.tsx rename to app/[locale]/home/location/[id]/edit/page.tsx diff --git a/app/[locale]/home/page.tsx b/app/[locale]/home/page.tsx new file mode 100644 index 0000000..92efeca --- /dev/null +++ b/app/[locale]/home/page.tsx @@ -0,0 +1,31 @@ +import { FC, Suspense } from 'react'; +import { Main } from '@/app/ui/Main'; +import HomePage from '@/app/ui/HomePage'; +import { MonthCardSkeleton } from '@/app/ui/MonthCardSkeleton'; + +export interface PageProps { + searchParams?: { + year?: string; + month?: string; + }; +} + +const HomePageSkeleton = () => +<> + + + + + +const Page:FC = async ({ searchParams }) => { + + return ( +
+ }> + + +
+ ); +} + +export default Page; \ No newline at end of file diff --git a/app/[locale]/print/[year]/[month]/not-found.tsx b/app/[locale]/home/print/[year]/[month]/not-found.tsx similarity index 100% rename from app/[locale]/print/[year]/[month]/not-found.tsx rename to app/[locale]/home/print/[year]/[month]/not-found.tsx diff --git a/app/[locale]/print/[year]/[month]/page.tsx b/app/[locale]/home/print/[year]/[month]/page.tsx similarity index 100% rename from app/[locale]/print/[year]/[month]/page.tsx rename to app/[locale]/home/print/[year]/[month]/page.tsx diff --git a/app/[locale]/year-month/[id]/add/page.tsx b/app/[locale]/home/year-month/[id]/add/page.tsx similarity index 100% rename from app/[locale]/year-month/[id]/add/page.tsx rename to app/[locale]/home/year-month/[id]/add/page.tsx diff --git a/app/[locale]/login/page.tsx b/app/[locale]/login/page.tsx deleted file mode 100644 index 0a3385d..0000000 --- a/app/[locale]/login/page.tsx +++ /dev/null @@ -1,109 +0,0 @@ -import { FC, ReactNode } from 'react'; -import { Main } from '@/app/ui/Main'; - -import { authConfig } from "@/app/lib/auth"; -import { SignInButton } from '@/app/ui/SignInButton'; -import Image from 'next/image'; -import { getTranslations } from "next-intl/server"; -import isWebview from "is-ua-webview"; -import { headers } from 'next/headers' -import { ExclamationTriangleIcon } from "@heroicons/react/24/outline"; - -type Provider = { - id: string; - name: string; - type: string; - style: { - logo: string; - bg: string; - text: string; - }; -}; - -function getProviders(): Provider[] { - const providerKeys: (keyof Provider)[] = ["id", "name", "type", "style"]; - return authConfig.providers.map((provider) => - getKeyValuesFromObject(provider, providerKeys) - ); -} - -function getKeyValuesFromObject(obj: any, keys: (keyof T)[]): T { - return keys.reduce((acc, key) => { - if (obj[key]) { - acc[key] = obj[key]; - } - return acc; - }, {} as T); -} - -const Page:FC = async () => { - - const providers = await getProviders(); - const t = await getTranslations("login-page"); - // get userAgent from NextJS - - const headersList = headers(); - const userAgent = headersList.get("user-agent") as string; - - const insideWebeview = isWebview(userAgent); - - return ( -
-

- {t("main-card.title-1")} - {t("main-card.title-2")} - {t("main-card.title-3")} -

-

{t("main-card.text-1")}

-

{t("main-card.text-2")}

- { - // Google will refuse OAuth signin if it's inside a webview (i.e. Facebook) - insideWebeview && -
-
- -
-
- { - t.rich("main-card.in-app-browser-warning", { - br: () =>
, - strong: (chunks:ReactNode) => {chunks}, - hint: (chunks:ReactNode) => {chunks} - }) - } -
-
- } - - { - Object.values(providers).map((provider) => ( -
- -
- )) - } -
- - -

{t("card-1.title")}

-

{t("card-1.text")}

- - -

{t("card-2.title")}

-

{t("card-2.text")}

- Boje označavaju status računa - -

{t("card-3.title")}

-

{t("card-3.text")}

- -
- ); -} - -export default Page; \ No newline at end of file diff --git a/app/[locale]/page.tsx b/app/[locale]/page.tsx index 92efeca..0a3385d 100644 --- a/app/[locale]/page.tsx +++ b/app/[locale]/page.tsx @@ -1,29 +1,107 @@ -import { FC, Suspense } from 'react'; +import { FC, ReactNode } from 'react'; import { Main } from '@/app/ui/Main'; -import HomePage from '@/app/ui/HomePage'; -import { MonthCardSkeleton } from '@/app/ui/MonthCardSkeleton'; -export interface PageProps { - searchParams?: { - year?: string; - month?: string; +import { authConfig } from "@/app/lib/auth"; +import { SignInButton } from '@/app/ui/SignInButton'; +import Image from 'next/image'; +import { getTranslations } from "next-intl/server"; +import isWebview from "is-ua-webview"; +import { headers } from 'next/headers' +import { ExclamationTriangleIcon } from "@heroicons/react/24/outline"; + +type Provider = { + id: string; + name: string; + type: string; + style: { + logo: string; + bg: string; + text: string; }; +}; + +function getProviders(): Provider[] { + const providerKeys: (keyof Provider)[] = ["id", "name", "type", "style"]; + return authConfig.providers.map((provider) => + getKeyValuesFromObject(provider, providerKeys) + ); } -const HomePageSkeleton = () => -<> - - - - +function getKeyValuesFromObject(obj: any, keys: (keyof T)[]): T { + return keys.reduce((acc, key) => { + if (obj[key]) { + acc[key] = obj[key]; + } + return acc; + }, {} as T); +} -const Page:FC = async ({ searchParams }) => { +const Page:FC = async () => { + + const providers = await getProviders(); + const t = await getTranslations("login-page"); + // get userAgent from NextJS + + const headersList = headers(); + const userAgent = headersList.get("user-agent") as string; + + const insideWebeview = isWebview(userAgent); return (
- }> - - +

+ {t("main-card.title-1")} + {t("main-card.title-2")} + {t("main-card.title-3")} +

+

{t("main-card.text-1")}

+

{t("main-card.text-2")}

+ { + // Google will refuse OAuth signin if it's inside a webview (i.e. Facebook) + insideWebeview && +
+
+ +
+
+ { + t.rich("main-card.in-app-browser-warning", { + br: () =>
, + strong: (chunks:ReactNode) => {chunks}, + hint: (chunks:ReactNode) => {chunks} + }) + } +
+
+ } + + { + Object.values(providers).map((provider) => ( +
+ +
+ )) + } +
+ + +

{t("card-1.title")}

+

{t("card-1.text")}

+ + +

{t("card-2.title")}

+

{t("card-2.text")}

+ Boje označavaju status računa + +

{t("card-3.title")}

+

{t("card-3.text")}

+
); } diff --git a/app/lib/actions/navigationActions.ts b/app/lib/actions/navigationActions.ts index 376e267..ae7615c 100644 --- a/app/lib/actions/navigationActions.ts +++ b/app/lib/actions/navigationActions.ts @@ -5,14 +5,14 @@ import { redirect } from 'next/navigation'; import { YearMonth } from "../db-types"; export async function gotoHome({year, month}: YearMonth) { - const path = `/?year=${year}&month=${month}`; + const path = `/home?year=${year}&month=${month}`; await gotoUrl(path); } export async function gotoHomeWithMessage(locale: string, message: string, yearMonth?: YearMonth) { const path = yearMonth - ? `/${locale}?year=${yearMonth.year}&month=${yearMonth.month}&${message}=true` - : `/${locale}?${message}=true`; + ? `/${locale}/home?year=${yearMonth.year}&month=${yearMonth.month}&${message}=true` + : `/${locale}/home?${message}=true`; await gotoUrl(path); } diff --git a/app/lib/auth.ts b/app/lib/auth.ts index dac126a..151d9a9 100644 --- a/app/lib/auth.ts +++ b/app/lib/auth.ts @@ -88,7 +88,7 @@ export const authConfig: NextAuthConfig = { strategy: 'jwt' }, pages: { - signIn: `/${defaultLocale}/login`, + signIn: `/${defaultLocale}`, }, }; diff --git a/app/ui/AddLocationButton.tsx b/app/ui/AddLocationButton.tsx index 52b408e..2154559 100644 --- a/app/ui/AddLocationButton.tsx +++ b/app/ui/AddLocationButton.tsx @@ -17,7 +17,7 @@ export const AddLocationButton:React.FC = ({yearMonth}) return(
- + diff --git a/app/ui/AddMonthButton.tsx b/app/ui/AddMonthButton.tsx index 2c0dd7c..2b2a3f2 100644 --- a/app/ui/AddMonthButton.tsx +++ b/app/ui/AddMonthButton.tsx @@ -18,7 +18,7 @@ export const AddMonthButton:React.FC = ({ yearMonth }) => { return(
- + diff --git a/app/ui/BillBadge.tsx b/app/ui/BillBadge.tsx index 8de5201..9496098 100644 --- a/app/ui/BillBadge.tsx +++ b/app/ui/BillBadge.tsx @@ -8,6 +8,6 @@ export interface BillBadgeProps { }; export const BillBadge:FC = ({ locationId, bill: { _id: billId, name, paid, hasAttachment }}) => - + {name} ; \ No newline at end of file diff --git a/app/ui/BillDeleteForm.tsx b/app/ui/BillDeleteForm.tsx index 77d39ae..cc46b6b 100644 --- a/app/ui/BillDeleteForm.tsx +++ b/app/ui/BillDeleteForm.tsx @@ -62,7 +62,7 @@ export const BillDeleteForm:FC = ({ bill, location }) => {
- {t("cancel-button")} + {t("cancel-button")}
diff --git a/app/ui/BillEditForm.tsx b/app/ui/BillEditForm.tsx index 44ec9ed..0e9d7f9 100644 --- a/app/ui/BillEditForm.tsx +++ b/app/ui/BillEditForm.tsx @@ -122,7 +122,7 @@ export const BillEditForm: FC = ({ location, bill }) => { { // don't show the delete button if we are adding a new bill bill ? - + : null } diff --git a/app/ui/LocationCard.tsx b/app/ui/LocationCard.tsx index bbb00f9..a434b35 100644 --- a/app/ui/LocationCard.tsx +++ b/app/ui/LocationCard.tsx @@ -44,7 +44,7 @@ export const LocationCard: FC = ({ location, currency }) => { return (
- +

{formatYearMonth(yearMonth)} {name}

@@ -58,7 +58,7 @@ export const LocationCard: FC = ({ location, currency }) => { ) : null }
- + {t("add-bill-button-tooltip")} diff --git a/app/ui/LocationDeleteForm.tsx b/app/ui/LocationDeleteForm.tsx index c51b456..5fa6c3d 100644 --- a/app/ui/LocationDeleteForm.tsx +++ b/app/ui/LocationDeleteForm.tsx @@ -58,7 +58,7 @@ export const LocationDeleteForm:FC = ({ location }) => )}
- {t("cancel-button")} + {t("cancel-button")}
diff --git a/app/ui/LocationEditForm.tsx b/app/ui/LocationEditForm.tsx index b2b8eb0..31c4fed 100644 --- a/app/ui/LocationEditForm.tsx +++ b/app/ui/LocationEditForm.tsx @@ -61,7 +61,7 @@ export const LocationEditForm: FC = ({ location, yearMont
{ location && - + } diff --git a/app/ui/MonthLocationList.tsx b/app/ui/MonthLocationList.tsx index 767ff56..00668ce 100644 --- a/app/ui/MonthLocationList.tsx +++ b/app/ui/MonthLocationList.tsx @@ -106,10 +106,10 @@ export const MonthLocationList:React.FC = ({ const handleMonthToggle = (yearMonth:YearMonth) => { // if the month is already expanded, collapse it if(expandedMonth === yearMonth.month) { - // router.push(`/?year=${yearMonth.year}`); + // router.push(`/home?year=${yearMonth.year}`); setExpandedMonth(-1); // no month is expanded } else { - // router.push(`/?year=${yearMonth.year}&month=${yearMonth.month}`); + // router.push(`/home?year=${yearMonth.year}&month=${yearMonth.month}`); setExpandedMonth(yearMonth.month); } } diff --git a/app/ui/NotFoundPage.tsx b/app/ui/NotFoundPage.tsx index 95301b9..9388412 100644 --- a/app/ui/NotFoundPage.tsx +++ b/app/ui/NotFoundPage.tsx @@ -12,7 +12,7 @@ export const NotFoundPage:FC = ({ title="404 Not Found", desc

{title}

{description}

- + Go Back \ No newline at end of file diff --git a/app/ui/PageFooter.tsx b/app/ui/PageFooter.tsx index 7fedf90..cd776d3 100644 --- a/app/ui/PageFooter.tsx +++ b/app/ui/PageFooter.tsx @@ -16,7 +16,7 @@ export const PageFooter: React.FC = () => {
Režije

{t('app-description')}

- {t('links.home')} + {t('links.home')} {t('links.privacy-policy')} {t('links.terms-of-service')}
diff --git a/app/ui/PageHeader.tsx b/app/ui/PageHeader.tsx index 04d2b15..64dc674 100644 --- a/app/ui/PageHeader.tsx +++ b/app/ui/PageHeader.tsx @@ -5,10 +5,10 @@ import AccountCircle from "@mui/icons-material/AccountCircle"; export const PageHeader = () =>
- logo Režije + logo Režije   - +
\ No newline at end of file diff --git a/app/ui/PrintButton.tsx b/app/ui/PrintButton.tsx index 93b99a8..5ea4b2d 100644 --- a/app/ui/PrintButton.tsx +++ b/app/ui/PrintButton.tsx @@ -12,7 +12,7 @@ export const PrintButton: React.FC = ({ yearMonth }) => { const t = useTranslations("home-page.month-card"); const handlePrintClick = () => { - window.open(`/print/${yearMonth.year}/${yearMonth.month}`, '_blank'); + window.open(`/home/print/${yearMonth.year}/${yearMonth.month}`, '_blank'); }; return ( diff --git a/app/ui/SignInButton.tsx b/app/ui/SignInButton.tsx index bc0f138..ea651c3 100644 --- a/app/ui/SignInButton.tsx +++ b/app/ui/SignInButton.tsx @@ -21,7 +21,7 @@ export const SignInButton:React.FC<{ provider: {id:string, name:string} }> = ({ const t = useTranslations("login-page"); return( -