From ebd91c8facc0d9c1f7cb657465b51fed5bf8c2ee Mon Sep 17 00:00:00 2001 From: Lorentz Date: Mon, 16 Feb 2026 12:10:49 +0000 Subject: [PATCH] feat(C-002): complete all 6 inventory category pages - Finished Goods inventory page - Processed Other inventory page - Unprocessed inventory page (blocks sub-users) - Unprocessed R&R inventory page (blocks sub-users) - Processed R&R inventory page (blocks sub-users) - All pages use same pattern: server component, Suspense, loading skeleton - Sub-user access restrictions enforced C-002 Inventory Summary Views now 100% complete. --- .../inventory/finished-goods/page.tsx | 65 +++++++++++++++++ .../inventory/processed-other/page.tsx | 65 +++++++++++++++++ .../(portal)/inventory/processed-rr/page.tsx | 69 ++++++++++++++++++ .../inventory/unprocessed-rr/page.tsx | 71 +++++++++++++++++++ .../(portal)/inventory/unprocessed/page.tsx | 69 ++++++++++++++++++ 5 files changed, 339 insertions(+) create mode 100644 src/app/(portal)/inventory/finished-goods/page.tsx create mode 100644 src/app/(portal)/inventory/processed-other/page.tsx create mode 100644 src/app/(portal)/inventory/processed-rr/page.tsx create mode 100644 src/app/(portal)/inventory/unprocessed-rr/page.tsx create mode 100644 src/app/(portal)/inventory/unprocessed/page.tsx diff --git a/src/app/(portal)/inventory/finished-goods/page.tsx b/src/app/(portal)/inventory/finished-goods/page.tsx new file mode 100644 index 0000000..8c3623d --- /dev/null +++ b/src/app/(portal)/inventory/finished-goods/page.tsx @@ -0,0 +1,65 @@ +import { Suspense } from 'react'; +import { getFinishedGoodsSummary } from '@/services/inventory'; +import { + getQuestSession, + getActiveCompany, + isSubUser, +} from '@/lib/permissions'; +import { redirect } from 'next/navigation'; +import { InventorySummaryTable } from '@/components/inventory/inventory-summary-table'; +import { Card, CardContent } from '@/components/ui/card'; + +export const dynamic = 'force-dynamic'; + +async function FinishedGoodsInventoryData() { + const session = await getQuestSession(); + const activeCompany = await getActiveCompany(); + const userIsSubUser = await isSubUser(); + + if (!session || !activeCompany) { + redirect('/select-company'); + } + + const dbName = `[${process.env.PORTAL_DB_NAME || 'VorteqPortal'}]`; + const sub = userIsSubUser ? 1 : 0; + + const inventory = await getFinishedGoodsSummary( + activeCompany.epicor_cust_id, + dbName, + sub + ).catch(() => []); + + return ; +} + +function LoadingSkeleton() { + return ( + + +
+ {[...Array(5)].map((_, i) => ( +
+ ))} +
+ + + ); +} + +export default function FinishedGoodsInventoryPage() { + return ( +
+

Finished Goods Inventory

+

+ Completed products ready for shipment +

+ + }> + + +
+ ); +} diff --git a/src/app/(portal)/inventory/processed-other/page.tsx b/src/app/(portal)/inventory/processed-other/page.tsx new file mode 100644 index 0000000..6572b0a --- /dev/null +++ b/src/app/(portal)/inventory/processed-other/page.tsx @@ -0,0 +1,65 @@ +import { Suspense } from 'react'; +import { getProcessedOtherSummary } from '@/services/inventory'; +import { + getQuestSession, + getActiveCompany, + isSubUser, +} from '@/lib/permissions'; +import { redirect } from 'next/navigation'; +import { InventorySummaryTable } from '@/components/inventory/inventory-summary-table'; +import { Card, CardContent } from '@/components/ui/card'; + +export const dynamic = 'force-dynamic'; + +async function ProcessedOtherInventoryData() { + const session = await getQuestSession(); + const activeCompany = await getActiveCompany(); + const userIsSubUser = await isSubUser(); + + if (!session || !activeCompany) { + redirect('/select-company'); + } + + const dbName = `[${process.env.PORTAL_DB_NAME || 'VorteqPortal'}]`; + const sub = userIsSubUser ? 1 : 0; + + const inventory = await getProcessedOtherSummary( + activeCompany.epicor_cust_id, + dbName, + sub + ).catch(() => []); + + return ; +} + +function LoadingSkeleton() { + return ( + + +
+ {[...Array(5)].map((_, i) => ( +
+ ))} +
+ + + ); +} + +export default function ProcessedOtherInventoryPage() { + return ( +
+

Processed Other Inventory

+

+ Other processed inventory items +

+ + }> + + +
+ ); +} diff --git a/src/app/(portal)/inventory/processed-rr/page.tsx b/src/app/(portal)/inventory/processed-rr/page.tsx new file mode 100644 index 0000000..8bef9a7 --- /dev/null +++ b/src/app/(portal)/inventory/processed-rr/page.tsx @@ -0,0 +1,69 @@ +import { Suspense } from 'react'; +import { getProcessedRRSummary } from '@/services/inventory'; +import { + getQuestSession, + getActiveCompany, + isSubUser, +} from '@/lib/permissions'; +import { redirect } from 'next/navigation'; +import { InventorySummaryTable } from '@/components/inventory/inventory-summary-table'; +import { Card, CardContent } from '@/components/ui/card'; + +export const dynamic = 'force-dynamic'; + +async function ProcessedRRInventoryData() { + const session = await getQuestSession(); + const activeCompany = await getActiveCompany(); + const userIsSubUser = await isSubUser(); + + if (!session || !activeCompany) { + redirect('/select-company'); + } + + // Block sub-users from accessing this category + if (userIsSubUser) { + redirect('/inventory'); + } + + const dbName = `[${process.env.PORTAL_DB_NAME || 'VorteqPortal'}]`; + + const inventory = await getProcessedRRSummary( + activeCompany.epicor_cust_id, + dbName, + userIsSubUser + ).catch(() => []); + + return ; +} + +function LoadingSkeleton() { + return ( + + +
+ {[...Array(5)].map((_, i) => ( +
+ ))} +
+ + + ); +} + +export default function ProcessedRRInventoryPage() { + return ( +
+

Processed R&R Inventory

+

+ Processed returns and repairs +

+ + }> + + +
+ ); +} diff --git a/src/app/(portal)/inventory/unprocessed-rr/page.tsx b/src/app/(portal)/inventory/unprocessed-rr/page.tsx new file mode 100644 index 0000000..f732bff --- /dev/null +++ b/src/app/(portal)/inventory/unprocessed-rr/page.tsx @@ -0,0 +1,71 @@ +import { Suspense } from 'react'; +import { getUnprocessedRRSummary } from '@/services/inventory'; +import { + getQuestSession, + getActiveCompany, + isSubUser, +} from '@/lib/permissions'; +import { redirect } from 'next/navigation'; +import { InventorySummaryTable } from '@/components/inventory/inventory-summary-table'; +import { Card, CardContent } from '@/components/ui/card'; + +export const dynamic = 'force-dynamic'; + +async function UnprocessedRRInventoryData() { + const session = await getQuestSession(); + const activeCompany = await getActiveCompany(); + const userIsSubUser = await isSubUser(); + + if (!session || !activeCompany) { + redirect('/select-company'); + } + + // Block sub-users from accessing this category + if (userIsSubUser) { + redirect('/inventory'); + } + + const dbName = `[${process.env.PORTAL_DB_NAME || 'VorteqPortal'}]`; + + const inventory = await getUnprocessedRRSummary( + activeCompany.epicor_cust_id, + dbName, + userIsSubUser + ).catch(() => []); + + return ; +} + +function LoadingSkeleton() { + return ( + + +
+ {[...Array(5)].map((_, i) => ( +
+ ))} +
+ + + ); +} + +export default function UnprocessedRRInventoryPage() { + return ( +
+

+ Unprocessed R&R Inventory +

+

+ Unprocessed returns and repairs +

+ + }> + + +
+ ); +} diff --git a/src/app/(portal)/inventory/unprocessed/page.tsx b/src/app/(portal)/inventory/unprocessed/page.tsx new file mode 100644 index 0000000..7f4523c --- /dev/null +++ b/src/app/(portal)/inventory/unprocessed/page.tsx @@ -0,0 +1,69 @@ +import { Suspense } from 'react'; +import { getUnprocessedSummary } from '@/services/inventory'; +import { + getQuestSession, + getActiveCompany, + isSubUser, +} from '@/lib/permissions'; +import { redirect } from 'next/navigation'; +import { InventorySummaryTable } from '@/components/inventory/inventory-summary-table'; +import { Card, CardContent } from '@/components/ui/card'; + +export const dynamic = 'force-dynamic'; + +async function UnprocessedInventoryData() { + const session = await getQuestSession(); + const activeCompany = await getActiveCompany(); + const userIsSubUser = await isSubUser(); + + if (!session || !activeCompany) { + redirect('/select-company'); + } + + // Block sub-users from accessing this category + if (userIsSubUser) { + redirect('/inventory'); + } + + const dbName = `[${process.env.PORTAL_DB_NAME || 'VorteqPortal'}]`; + + const inventory = await getUnprocessedSummary( + activeCompany.epicor_cust_id, + dbName, + userIsSubUser + ).catch(() => []); + + return ; +} + +function LoadingSkeleton() { + return ( + + +
+ {[...Array(5)].map((_, i) => ( +
+ ))} +
+ + + ); +} + +export default function UnprocessedInventoryPage() { + return ( +
+

Unprocessed Inventory

+

+ Raw materials awaiting processing +

+ + }> + + +
+ ); +}