CRITICAL FIXES: - Fix noAsyncPromiseExecutor in xcoba.ts and xcoba2.ts * Removed async promise executor pattern * Refactored to proper promise chain with .then()/.catch() * Added proper error handling for unhandled rejections - Fix useIterableCallbackReturn in seed_berita.ts * Replaced forEach with for...of loop to avoid returning values in callbacks MEDIUM FIXES: - Fix useNodejsImportProtocol (728 files auto-fixed) * Updated Node.js builtin imports to use node: protocol * Files: eslint.config.mjs, vitest.config.ts, zgen/image.ts, and 725+ more - Fix useOptionalChain in xcoba.ts (auto-fixed) * Changed 'resOut && resOut.body' to 'resOut?.body' - Fix noImportantStyles in dark-mode-table.css * Added biome-ignore suppression comments with justification * Required to override Mantine UI library styles - Fix noUselessContinue in find-port.ts (auto-fixed) * Removed unnecessary continue statement - Fix useLiteralKeys (700+ files auto-fixed) * Simplified computed expressions to use literal keys * Example: obj['create'] -> obj.create RESULTS: - Errors reduced: 4,516 → 3,521 (-22%) - Warnings reduced: 3,861 → 2,083 (-46%) - Total issues reduced: 8,991 → 6,115 (-32%) - 735 files auto-fixed by biome lint --fix Remaining issues (~6,115): - Mostly noExplicitAny warnings requiring manual refactoring - Will be addressed in gradual code quality improvements Co-authored-by: Qwen-Coder <qwen-coder@alibabacloud.com>
164 lines
4.9 KiB
TypeScript
164 lines
4.9 KiB
TypeScript
/* eslint-disable react-hooks/exhaustive-deps */
|
|
'use client'
|
|
import colors from '@/con/colors';
|
|
import {
|
|
Box,
|
|
ScrollArea,
|
|
Stack,
|
|
Tabs,
|
|
TabsList,
|
|
TabsPanel,
|
|
TabsTab,
|
|
Title
|
|
} from '@mantine/core';
|
|
import { IconCategory, IconShoppingBag } from '@tabler/icons-react';
|
|
import { usePathname, useRouter } from 'next/navigation';
|
|
import type React from 'react';
|
|
import { useEffect, useState } from 'react';
|
|
|
|
function LayoutTabs({ children }: { children: React.ReactNode }) {
|
|
const router = useRouter();
|
|
const pathname = usePathname();
|
|
|
|
const tabs = [
|
|
{
|
|
label: "Produk Pasar Desa",
|
|
value: "produkpasardesa",
|
|
href: "/admin/ekonomi/pasar-desa/produk-pasar-desa",
|
|
icon: <IconShoppingBag size={18} stroke={1.8} />
|
|
},
|
|
{
|
|
label: "Kategori Produk",
|
|
value: "kategoriproduk",
|
|
href: "/admin/ekonomi/pasar-desa/kategori-produk",
|
|
icon: <IconCategory size={18} stroke={1.8} />
|
|
},
|
|
];
|
|
|
|
const currentTab = tabs.find((tab) => tab.href === pathname);
|
|
const [activeTab, setActiveTab] = useState<string | null>(
|
|
currentTab?.value || tabs[0].value
|
|
);
|
|
|
|
const handleTabChange = (value: string | null) => {
|
|
const tab = tabs.find((t) => t.value === value);
|
|
if (tab) {
|
|
router.push(tab.href);
|
|
}
|
|
setActiveTab(value);
|
|
};
|
|
|
|
useEffect(() => {
|
|
const match = tabs.find((tab) => tab.href === pathname);
|
|
if (match) {
|
|
setActiveTab(match.value);
|
|
}
|
|
}, [pathname]);
|
|
|
|
return (
|
|
<Stack gap="lg">
|
|
<Title order={2} fw={700} style={{ color: "#1A1B1E" }}>
|
|
Pasar Desa
|
|
</Title>
|
|
|
|
<Tabs
|
|
color={colors['blue-button']}
|
|
variant="pills"
|
|
value={activeTab}
|
|
onChange={handleTabChange}
|
|
radius="lg"
|
|
keepMounted={false}
|
|
>
|
|
{/* ✅ Scroll horizontal wrapper */}
|
|
<Box visibleFrom='md' pb={10}>
|
|
<ScrollArea type="auto" offsetScrollbars>
|
|
<TabsList
|
|
p="sm"
|
|
style={{
|
|
background: "linear-gradient(135deg, #e7ebf7, #f9faff)",
|
|
borderRadius: "1rem",
|
|
boxShadow: "inset 0 0 10px rgba(0,0,0,0.05)",
|
|
display: "flex",
|
|
flexWrap: "nowrap",
|
|
gap: "0.5rem",
|
|
paddingInline: "0.5rem", // ✅ biar nggak nempel ke tepi
|
|
}}
|
|
>
|
|
{tabs.map((tab, i) => (
|
|
<TabsTab
|
|
key={i}
|
|
value={tab.value}
|
|
leftSection={tab.icon}
|
|
style={{
|
|
fontWeight: 600,
|
|
fontSize: "0.9rem",
|
|
transition: "all 0.2s ease",
|
|
flexShrink: 0, // ✅ jangan mengecil aneh-aneh
|
|
}}
|
|
>
|
|
{tab.label}
|
|
</TabsTab>
|
|
))}
|
|
</TabsList>
|
|
</ScrollArea>
|
|
</Box>
|
|
|
|
<Box hiddenFrom='md' pb={10}>
|
|
<ScrollArea
|
|
type="auto"
|
|
offsetScrollbars={false}
|
|
w="100%"
|
|
>
|
|
|
|
<TabsList
|
|
p="xs" // lebih kecil
|
|
style={{
|
|
background: "linear-gradient(135deg, #e7ebf7, #f9faff)",
|
|
borderRadius: "1rem",
|
|
display: "flex",
|
|
flexWrap: "nowrap",
|
|
gap: "0.5rem",
|
|
width: "max-content", // ⬅️ kunci
|
|
maxWidth: "100%", // ⬅️ penting
|
|
}}
|
|
>
|
|
{tabs.map((tab, i) => (
|
|
<TabsTab
|
|
key={i}
|
|
value={tab.value}
|
|
leftSection={tab.icon}
|
|
style={{
|
|
fontWeight: 600,
|
|
fontSize: "0.9rem",
|
|
paddingInline: "0.75rem", // ⬅️ lebih ramping
|
|
flexShrink: 0, // ✅ jangan mengecil aneh-aneh
|
|
}}
|
|
>
|
|
{tab.label}
|
|
</TabsTab>
|
|
))}
|
|
</TabsList>
|
|
</ScrollArea>
|
|
</Box>
|
|
|
|
{tabs.map((tab, i) => (
|
|
<TabsPanel
|
|
key={i}
|
|
value={tab.value}
|
|
style={{
|
|
padding: "1.5rem",
|
|
background: "linear-gradient(180deg, #ffffff, #f5f6fa)",
|
|
borderRadius: "1rem",
|
|
boxShadow: "0 4px 16px rgba(0,0,0,0.05)",
|
|
}}
|
|
>
|
|
{children}
|
|
</TabsPanel>
|
|
))}
|
|
</Tabs>
|
|
</Stack>
|
|
);
|
|
}
|
|
|
|
export default LayoutTabs;
|