Skip to content
Merged
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
18 changes: 18 additions & 0 deletions frontend/src/app/[lang]/donated-items/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"use client";

import PageErrorState from "@/common/components/page-error-state";

type DonatedItemsErrorProps = {
error: Error;
reset: () => void;
};

export default function DonatedItemsError({ error: _error, reset }: DonatedItemsErrorProps) {
return (
<PageErrorState
title="Failed to load page"
message="Please try again in a moment."
onRetry={reset}
/>
);
}
13 changes: 3 additions & 10 deletions frontend/src/app/[lang]/donated-items/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { Suspense } from "react";

const LIMIT = 9;

interface Props {
type Props = {
params: Promise<{ lang: LocaleType}>;
searchParams: Promise< { page?: string }>;
}
Expand All @@ -20,20 +20,13 @@ export default async function Items(props: Props) {
const currentPage = Number(searchParams?.page) || 1;

const response = await fetch(`${BASE_URL}/items?page=${currentPage}&limit=${LIMIT}`);

const data: EntitiesResponse<ItemType> = await response.json();

const { entities, metadata } = data;

if (!entities) {
return (
<div className="min-h-screen flex justify-center items-center">
<CircularProgress color="primary" />
</div>
);
}

return (
<Suspense fallback={<div>Loading...</div>}>
<Suspense fallback={<CircularProgress color="primary" />}>
<DonatedItemsView items={entities} metadata={metadata} />
</Suspense>
);
Expand Down
18 changes: 18 additions & 0 deletions frontend/src/app/[lang]/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
"use client";

import PageErrorState from "@/common/components/page-error-state";

type HomeErrorProps = {
error: Error;
reset: () => void;
};

export default function HomeError({ error: _error, reset }: HomeErrorProps) {
return (
<PageErrorState
title="Failed to load page"
message="Please try again in a moment."
onRetry={reset}
/>
);
}
Original file line number Diff line number Diff line change
@@ -1,24 +1,24 @@
import { Button } from '@mui/material';
import Link from 'next/link';

import {navRoutes} from '@/common/routes/route-configs';
import { useRouter } from 'next/navigation';
import { useLocale, useTranslations } from 'next-intl';
import { getLocalizedPath } from '@/common/routes/url-configs';

const NavBarItems = () => {
const locale = useLocale();
const t = useTranslations('common.nav-bar');
const router = useRouter();

return (
<ul className="font-medium flex flex-col p-4 md:p-0 mt-4 border border-gray-100 rounded-lg bg-gray-50 md:flex-row md:space-x-8 rtl:space-x-reverse md:mt-0 md:border-0 md:bg-white dark:bg-gray-800 md:dark:bg-gray-900 dark:border-gray-700">
{ navRoutes.map(item => {
const localizedPath = getLocalizedPath(locale, item.path);
return (
<li key={item.key}>
<Button
variant='text'
onClick={() => router.push(getLocalizedPath(locale, item.path))}
href={getLocalizedPath(locale, item.path)}
component={Link}
href={localizedPath}
className='text-gray-800'
>
{t(item.key)}
Expand Down
5 changes: 2 additions & 3 deletions frontend/src/common/components/navigation-bar/nav-bar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,11 @@ import { getLocalizedPath, urlConfigs } from "@/common/routes/url-configs";
import NavBarItems from "./nav-bar-item";
import { Button } from "@mui/material";
import LanguageSelection from "../language-selection";
import { useRouter } from "next/navigation";
import { useLocale, useTranslations } from "next-intl";

const NavBar = () => {
const [isOpen, setIsOpen] = useState(false);

const router = useRouter();
const pathname = usePathname();
const locale = useLocale();
const t = useTranslations("common.nav-bar");
Expand Down Expand Up @@ -58,8 +56,9 @@ const NavBar = () => {
<LanguageSelection />
<Button
variant="contained"
component={Link}
href={getLocalizedPath(locale, urlConfigs.donatedItems.create.path)}
className="hidden md:inline-block"
onClick={() => router.push(getLocalizedPath(locale, urlConfigs.donatedItems.create.path))}
>
{t("list-an-item")}
</Button>
Expand Down
31 changes: 31 additions & 0 deletions frontend/src/common/components/page-error-state.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Button } from "@mui/material";

type PageErrorStateProps = {
title?: string;
message?: string;
onRetry?: () => void;
};

const PageErrorState = ({
title = "Failed to load page",
message = "Please try again in a moment.",
onRetry,
}: PageErrorStateProps) => {
return (
<div className="min-h-screen flex flex-col items-center justify-center gap-4 px-4 text-center">
<h2 className="text-2xl font-semibold">{title}</h2>
<p className="text-gray-600">{message}</p>
{onRetry && (
<Button
variant="contained"
onClick={onRetry}
className="px-4 py-2"
>
Try again
</Button>
)}
</div>
);
};

export default PageErrorState;
3 changes: 2 additions & 1 deletion frontend/src/common/routes/url-configs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,6 @@ export const urlConfigs = {
}

export const getLocalizedPath = (locale: Locale, path: string) => {
return `/${locale}/${path}`;
const normalizedPath = path.replace(/^\/+/, "");
return normalizedPath ? `/${locale}/${normalizedPath}` : `/${locale}`;
}
10 changes: 10 additions & 0 deletions frontend/src/features/donated-items/donated-items-empty-state.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const DonatedItemsEmptyState = () => {
return (
<div className="min-h-screen flex flex-col items-center justify-center gap-3">
<h2 className="text-2xl font-semibold">No donated items yet</h2>
<p className="text-gray-600">Check back later or be the first to list one.</p>
</div>
);
};

export default DonatedItemsEmptyState;
7 changes: 6 additions & 1 deletion frontend/src/features/donated-items/donated-items-view.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,21 @@ import { Pagination } from "@mui/material";
import DonatedItemList from "./list/donated-item-list";
import { useTranslations } from "next-intl";
import { useDonatedItemsVM } from "./use-donated-items-vm";
import DonatedItemsEmptyState from "./donated-items-empty-state";

type DonatedItemsProps = {
items: ItemType[];
items?: ItemType[];
metadata: Metadata;
}

const DonatedItemsView = ({ items, metadata } : DonatedItemsProps) => {
const t = useTranslations("donated-items.list");
const { onChangePagination, page, totalPages, getSelectedItemPath } = useDonatedItemsVM({ metadata });

if (!items || items.length === 0) {
return <DonatedItemsEmptyState />;
}

return (
<div className="min-h-screen">
<h2
Expand Down
Loading