Fix financial page mobile layout, restore shop-discover category chips, unify chip height

- financial/page.tsx: the title+date and amount+status rows used a hard
  flex-col/flex-row breakpoint switch (sm:), so below 640px every row
  stacked into 4 separate lines instead of wrapping gracefully — now
  always flex-row with flex-wrap, min-w-0/shrink-0/truncate so long
  content wraps instead of the date/badge visually colliding
- shops/discover/page.tsx: restored the real category chips (fetched from
  /shop-categories) alongside All/Pinterest — my earlier pass replaced
  the whole filter row with just those two, dropping the categories the
  page never actually had a chance to keep
- buttonStyles.ts: btnFilterChip/btnFilterChipActive now have an explicit
  h-9 (matching toggleBtnClass, used right above them on the shop
  dashboard) instead of deriving height from padding alone, which made
  them visibly shorter than the buyer/seller toggle

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
payacom
2026-09-16 16:31:08 +03:30
parent 71da2b53fe
commit e31a08df41
3 changed files with 76 additions and 40 deletions

View File

@@ -103,33 +103,33 @@ export default function Financial() {
key={item._id}
className="p-5 border rounded-3xl border-neutral-200 dark:border-neutral-700 bg-white dark:bg-neutral-800 shadow-sm hover:shadow-md transition-all duration-200"
>
<div className="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-3 mb-3">
<div className="font-medium text-base md:text-lg text-neutral-900 dark:text-white flex items-center gap-2">
<div className="flex flex-wrap items-center justify-between gap-2 mb-3">
<div className="min-w-0 font-medium text-base md:text-lg text-neutral-900 dark:text-white flex items-center gap-2">
{getTransactionType(item.type)}
{item.project_title && (
<span className="text-sm text-neutral-500 dark:text-neutral-400">
<span className="truncate text-sm text-neutral-500 dark:text-neutral-400">
({item.project_title})
</span>
)}
</div>
<div className="text-sm text-neutral-500 dark:text-neutral-400 whitespace-nowrap">
<div className="shrink-0 text-sm text-neutral-500 dark:text-neutral-400 whitespace-nowrap">
{formatDate(item.createdAt)}
</div>
</div>
<div className="flex flex-col sm:flex-row sm:justify-between sm:items-center gap-4">
<div className="font-semibold text-lg text-neutral-900 dark:text-white">
<div className="flex flex-wrap items-center justify-between gap-3">
<div className="min-w-0 font-semibold text-lg text-neutral-900 dark:text-white">
{t("settings.financial.amountPaid")}:{" "}
{Number(item.amount).toLocaleString(amountLocale)}{" "}
{t("settings.toman")}
</div>
<div className="flex items-center gap-2">
<div className="flex shrink-0 items-center gap-2">
<span className="text-neutral-600 dark:text-neutral-300">
{t("settings.status")}:
</span>
<span
className={`font-medium px-4 py-1.5 rounded-full text-sm ${getStatusClass(
className={`font-medium px-4 py-1.5 rounded-full text-sm whitespace-nowrap ${getStatusClass(
item.status
)}`}
>

View File

@@ -1,6 +1,6 @@
"use client";
import { useState } from "react";
import { useEffect, useMemo, useState } from "react";
import Container from "@/components/elements/Container";
import LocalePageShell from "@/components/i18n/LocalePageShell";
import PageTitle from "@/components/settings/PageTitle";
@@ -9,18 +9,46 @@ import TabNavigation from "@/components/TabNavigation";
import ShopProductGrid from "@/components/shops/ShopProductGrid";
import BoldIcon from "@/components/ui/BoldIcon";
import { cn } from "@/lib/utils";
import useAxios from "@/hooks/useAxios";
import useInfiniteScroll from "@/hooks/useInfiniteScroll";
import { IShopProductListing } from "@/types/types";
import { useTranslation } from "react-i18next";
const ALL_ID = "__all__";
const PINTEREST_ID = "__pinterest__";
type ShopCategory = { category: string; sub_categories?: unknown[] };
export default function ShopDiscoverPage() {
const { t } = useTranslation("common");
const [pinterestOnly, setPinterestOnly] = useState(false);
const { request } = useAxios();
const [activeFilter, setActiveFilter] = useState<string>(ALL_ID);
const [categories, setCategories] = useState<string[]>([]);
useEffect(() => {
request<{ categories?: ShopCategory[] }>("GET", "/shop-categories", null, {
noToast: true,
})
.then((res) =>
setCategories(
(res?.categories ?? []).map((c) => c.category).filter(Boolean)
)
)
.catch(() => setCategories([]));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const chips = useMemo(() => [ALL_ID, PINTEREST_ID, ...categories], [categories]);
const { data, isLoading } = useInfiniteScroll({
endpoint: "/shop-products/discover",
queryKey: ["shop-products-discover", String(pinterestOnly)],
params: pinterestOnly ? { pinterest: "true" } : {},
queryKey: ["shop-products-discover", activeFilter],
params:
activeFilter === PINTEREST_ID
? { pinterest: "true" }
: activeFilter === ALL_ID
? {}
: { category: activeFilter },
});
const listings: IShopProductListing[] =
@@ -33,32 +61,37 @@ export default function ShopDiscoverPage() {
<Container className="pb-28">
<PageTitle>{t("shops.discoverTitle")}</PageTitle>
<div className="mb-3 flex items-center gap-2">
<button
type="button"
onClick={() => setPinterestOnly(false)}
className={cn(
"rounded-2xl border px-3.5 py-2 text-sm font-medium transition",
!pinterestOnly
? "border-pink-400 bg-pink-50 text-pink-600 dark:bg-pink-950/30"
: "border-neutral-200 text-neutral-700 dark:border-neutral-700 dark:text-neutral-300"
)}
>
{t("shops.allFilter")}
</button>
<button
type="button"
onClick={() => setPinterestOnly(true)}
className={cn(
"flex items-center gap-1.5 rounded-2xl border px-3.5 py-2 text-sm font-medium transition",
pinterestOnly
? "border-[#E60023] bg-[#E60023]/10 text-[#E60023]"
: "border-neutral-200 text-neutral-700 dark:border-neutral-700 dark:text-neutral-300"
)}
>
<BoldIcon name="pinterest" size={14} tinted />
{t("shops.pinterestFilter")}
</button>
<div className="mb-3 flex items-center gap-2 overflow-x-auto pb-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden">
{chips.map((c) => {
const active = activeFilter === c;
const isPinterest = c === PINTEREST_ID;
const label =
c === ALL_ID
? t("shops.allFilter")
: isPinterest
? t("shops.pinterestFilter")
: c;
return (
<button
key={c}
type="button"
onClick={() => setActiveFilter(c)}
className={cn(
"flex shrink-0 items-center gap-1.5 whitespace-nowrap rounded-2xl border px-3.5 py-2 text-sm font-medium transition",
active
? isPinterest
? "border-[#E60023] bg-[#E60023]/10 text-[#E60023]"
: "border-pink-400 bg-pink-50 text-pink-600 dark:bg-pink-950/30"
: "border-neutral-200 text-neutral-700 dark:border-neutral-700 dark:text-neutral-300"
)}
>
{isPinterest ? (
<BoldIcon name="pinterest" size={14} tinted />
) : null}
{label}
</button>
);
})}
</div>
<ShopProductGrid

View File

@@ -25,16 +25,19 @@ export const btnPrimary = cn(
export const btnSecondary = cn(btnDefault, "font-medium text-foreground/90");
// h-9 اضافه شد تا دقیقاً هم‌ارتفاعِ toggleBtnClass باشه (اونجا صریح h-9 پاس داده
// می‌شه) — قبلاً ارتفاعِ این چیپ‌ها فقط از py-1.5 می‌اومد و کوتاه‌تر از دکمه‌های
// toggle/تایید بود، با اینکه هر دو rounded-3xl (کاملاً pill) بودن
export const btnFilterChip = cn(
btnBase,
"rounded-3xl bg-white/90 px-4 py-1.5 text-xs font-semibold",
"flex h-9 items-center justify-center rounded-3xl bg-white/90 px-4 text-xs font-semibold",
BTN_BORDER,
"dark:bg-neutral-900/90"
);
export const btnFilterChipActive = cn(
btnBase,
"btn-modern--selected rounded-3xl px-4 py-1.5 text-xs font-semibold text-white",
"btn-modern--selected flex h-9 items-center justify-center rounded-3xl px-4 text-xs font-semibold text-white",
BTN_BORDER
);