diff --git a/src/frontend/src/components/render/ModelType.tsx b/src/frontend/src/components/render/ModelType.tsx index 11699d603f..ab66a71da9 100644 --- a/src/frontend/src/components/render/ModelType.tsx +++ b/src/frontend/src/components/render/ModelType.tsx @@ -36,7 +36,7 @@ export const ModelInformationDict: ModelDictory = { label: t`Supplier Part`, label_multiple: t`Supplier Parts`, url_overview: '/supplierpart', - url_detail: '/supplierpart/:pk/', + url_detail: '/purchasing/supplier-part/:pk/', cui_detail: '/supplier-part/:pk/', api_endpoint: ApiPaths.supplier_part_list }, @@ -44,7 +44,7 @@ export const ModelInformationDict: ModelDictory = { label: t`Manufacturer Part`, label_multiple: t`Manufacturer Parts`, url_overview: '/manufacturerpart', - url_detail: '/manufacturerpart/:pk/', + url_detail: '/purchasing/manufacturer-part/:pk/', cui_detail: '/manufacturer-part/:pk/', api_endpoint: ApiPaths.manufacturer_part_list }, diff --git a/src/frontend/src/components/tables/purchasing/ManufacturerPartTable.tsx b/src/frontend/src/components/tables/purchasing/ManufacturerPartTable.tsx index 2b2d03c758..2982e2e8e9 100644 --- a/src/frontend/src/components/tables/purchasing/ManufacturerPartTable.tsx +++ b/src/frontend/src/components/tables/purchasing/ManufacturerPartTable.tsx @@ -1,5 +1,6 @@ import { t } from '@lingui/macro'; import { ReactNode, useCallback, useMemo } from 'react'; +import { useNavigate } from 'react-router-dom'; import { ApiPaths } from '../../../enums/ApiEndpoints'; import { UserRoles } from '../../../enums/Roles'; @@ -23,6 +24,7 @@ export function ManufacturerPartTable({ params }: { params: any }): ReactNode { const table = useTable('manufacturerparts'); const user = useUserState(); + const navigate = useNavigate(); // Construct table columns for this table const tableColumns: TableColumn[] = useMemo(() => { @@ -127,7 +129,12 @@ export function ManufacturerPartTable({ params }: { params: any }): ReactNode { manufacturer_detail: true }, rowActions: rowActions, - tableActions: tableActions + tableActions: tableActions, + onRowClick: (record: any) => { + if (record?.pk) { + navigate(`/purchasing/manufacturer-part/${record.pk}/`); + } + } }} /> ); diff --git a/src/frontend/src/components/tables/purchasing/SupplierPartTable.tsx b/src/frontend/src/components/tables/purchasing/SupplierPartTable.tsx index c0b7272668..2e2bd7278b 100644 --- a/src/frontend/src/components/tables/purchasing/SupplierPartTable.tsx +++ b/src/frontend/src/components/tables/purchasing/SupplierPartTable.tsx @@ -1,6 +1,7 @@ import { t } from '@lingui/macro'; import { Text } from '@mantine/core'; import { ReactNode, useCallback, useMemo } from 'react'; +import { useNavigate } from 'react-router-dom'; import { ApiPaths } from '../../../enums/ApiEndpoints'; import { UserRoles } from '../../../enums/Roles'; @@ -26,6 +27,7 @@ export function SupplierPartTable({ params }: { params: any }): ReactNode { const table = useTable('supplierparts'); const user = useUserState(); + const navigate = useNavigate(); // Construct table columns for this table const tableColumns: TableColumn[] = useMemo(() => { @@ -229,7 +231,12 @@ export function SupplierPartTable({ params }: { params: any }): ReactNode { manufacturer_detail: true }, rowActions: rowActions, - tableActions: tableActions + tableActions: tableActions, + onRowClick: (record: any) => { + if (record?.pk) { + navigate(`/purchasing/supplier-part/${record.pk}/`); + } + } }} /> diff --git a/src/frontend/src/enums/ApiEndpoints.tsx b/src/frontend/src/enums/ApiEndpoints.tsx index 24388bec07..0dc5b5368c 100644 --- a/src/frontend/src/enums/ApiEndpoints.tsx +++ b/src/frontend/src/enums/ApiEndpoints.tsx @@ -66,6 +66,7 @@ export enum ApiPaths { company_attachment_list = 'api-company-attachment-list', supplier_part_list = 'api-supplier-part-list', manufacturer_part_list = 'api-manufacturer-part-list', + manufacturer_part_attachment_list = 'api-manufacturer-part-attachment-list', address_list = 'api-address-list', contact_list = 'api-contact-list', diff --git a/src/frontend/src/pages/company/CompanyDetail.tsx b/src/frontend/src/pages/company/CompanyDetail.tsx index 38c4c27f93..65b08a8eef 100644 --- a/src/frontend/src/pages/company/CompanyDetail.tsx +++ b/src/frontend/src/pages/company/CompanyDetail.tsx @@ -30,7 +30,9 @@ import { PanelType } from '../../components/nav/PanelGroup'; import { AddressTable } from '../../components/tables/company/AddressTable'; import { ContactTable } from '../../components/tables/company/ContactTable'; import { AttachmentTable } from '../../components/tables/general/AttachmentTable'; +import { ManufacturerPartTable } from '../../components/tables/purchasing/ManufacturerPartTable'; import { PurchaseOrderTable } from '../../components/tables/purchasing/PurchaseOrderTable'; +import { SupplierPartTable } from '../../components/tables/purchasing/SupplierPartTable'; import { ReturnOrderTable } from '../../components/tables/sales/ReturnOrderTable'; import { SalesOrderTable } from '../../components/tables/sales/SalesOrderTable'; import { StockItemTable } from '../../components/tables/stock/StockItemTable'; @@ -77,13 +79,19 @@ export default function CompanyDetail(props: CompanyDetailProps) { name: 'manufactured-parts', label: t`Manufactured Parts`, icon: , - hidden: !company?.is_manufacturer + hidden: !company?.is_manufacturer, + content: company?.pk && ( + + ) }, { name: 'supplied-parts', label: t`Supplied Parts`, icon: , - hidden: !company?.is_supplier + hidden: !company?.is_supplier, + content: company?.pk && ( + + ) }, { name: 'purchase-orders', diff --git a/src/frontend/src/pages/company/ManufacturerPartDetail.tsx b/src/frontend/src/pages/company/ManufacturerPartDetail.tsx new file mode 100644 index 0000000000..4be641aa3a --- /dev/null +++ b/src/frontend/src/pages/company/ManufacturerPartDetail.tsx @@ -0,0 +1,98 @@ +import { t } from '@lingui/macro'; +import { LoadingOverlay, Skeleton, Stack } from '@mantine/core'; +import { + IconBuildingWarehouse, + IconInfoCircle, + IconList, + IconPaperclip +} from '@tabler/icons-react'; +import { useMemo } from 'react'; +import { useParams } from 'react-router-dom'; + +import { PageDetail } from '../../components/nav/PageDetail'; +import { PanelGroup, PanelType } from '../../components/nav/PanelGroup'; +import { AttachmentTable } from '../../components/tables/general/AttachmentTable'; +import { SupplierPartTable } from '../../components/tables/purchasing/SupplierPartTable'; +import { ApiPaths } from '../../enums/ApiEndpoints'; +import { useInstance } from '../../hooks/UseInstance'; + +export default function ManufacturerPartDetail() { + const { id } = useParams(); + + const { instance: manufacturerPart, instanceQuery } = useInstance({ + endpoint: ApiPaths.manufacturer_part_list, + pk: id, + hasPrimaryKey: true, + params: { + part_detail: true, + manufacturer_detail: true + } + }); + + const panels: PanelType[] = useMemo(() => { + return [ + { + name: 'details', + label: t`Details`, + icon: + }, + { + name: 'parameters', + label: t`Parameters`, + icon: + }, + { + name: 'suppliers', + label: t`Suppliers`, + icon: , + content: manufacturerPart?.pk ? ( + + ) : ( + + ) + }, + { + name: 'attachments', + label: t`Attachments`, + icon: , + content: ( + + ) + } + ]; + }, [manufacturerPart]); + + const breadcrumbs = useMemo(() => { + return [ + { + name: t`Purchasing`, + url: '/purchasing/' + }, + { + name: manufacturerPart?.manufacturer_detail?.name ?? t`Manufacturer`, + url: `/company/manufacturer/${manufacturerPart?.manufacturer_detail?.id}/` + } + ]; + }, [manufacturerPart]); + + return ( + + + + + + ); +} diff --git a/src/frontend/src/pages/company/SupplierPartDetail.tsx b/src/frontend/src/pages/company/SupplierPartDetail.tsx new file mode 100644 index 0000000000..161dcffec2 --- /dev/null +++ b/src/frontend/src/pages/company/SupplierPartDetail.tsx @@ -0,0 +1,80 @@ +import { t } from '@lingui/macro'; +import { LoadingOverlay, Stack } from '@mantine/core'; +import { + IconCurrencyDollar, + IconInfoCircle, + IconPackages, + IconShoppingCart +} from '@tabler/icons-react'; +import { useMemo } from 'react'; +import { useParams } from 'react-router-dom'; + +import { PageDetail } from '../../components/nav/PageDetail'; +import { PanelGroup, PanelType } from '../../components/nav/PanelGroup'; +import { ApiPaths } from '../../enums/ApiEndpoints'; +import { useInstance } from '../../hooks/UseInstance'; + +export default function SupplierPartDetail() { + const { id } = useParams(); + + const { instance: supplierPart, instanceQuery } = useInstance({ + endpoint: ApiPaths.supplier_part_list, + pk: id, + hasPrimaryKey: true, + params: { + part_detail: true, + supplier_detail: true + } + }); + + const panels: PanelType[] = useMemo(() => { + return [ + { + name: 'details', + label: t`Details`, + icon: + }, + { + name: 'stock', + label: t`Received Stock`, + icon: + }, + { + name: 'purchaseorders', + label: t`Purchase Orders`, + icon: + }, + { + name: 'pricing', + label: t`Pricing`, + icon: + } + ]; + }, []); + + const breadcrumbs = useMemo(() => { + return [ + { + name: t`Purchasing`, + url: '/purchasing/' + }, + { + name: supplierPart?.supplier_detail?.name ?? t`Supplier`, + url: `/company/supplier/${supplierPart?.supplier_detail?.pk ?? ''}` + } + ]; + }, [supplierPart]); + + return ( + + + + + + ); +} diff --git a/src/frontend/src/router.tsx b/src/frontend/src/router.tsx index dd82991751..c376dab343 100644 --- a/src/frontend/src/router.tsx +++ b/src/frontend/src/router.tsx @@ -28,6 +28,14 @@ export const ManufacturerDetail = Loadable( lazy(() => import('./pages/company/ManufacturerDetail')) ); +export const SupplierPartDetail = Loadable( + lazy(() => import('./pages/company/SupplierPartDetail')) +); + +export const ManufacturerPartDetail = Loadable( + lazy(() => import('./pages/company/ManufacturerPartDetail')) +); + export const CategoryDetail = Loadable( lazy(() => import('./pages/part/CategoryDetail')) ); @@ -137,7 +145,12 @@ export const routes = ( } /> } /> } /> + } /> } /> + } + /> } /> diff --git a/src/frontend/src/states/ApiState.tsx b/src/frontend/src/states/ApiState.tsx index 86e986dc74..6c17f8c98f 100644 --- a/src/frontend/src/states/ApiState.tsx +++ b/src/frontend/src/states/ApiState.tsx @@ -181,6 +181,8 @@ export function apiEndpoint(path: ApiPaths): string { return 'company/part/'; case ApiPaths.manufacturer_part_list: return 'company/part/manufacturer/'; + case ApiPaths.manufacturer_part_attachment_list: + return 'company/part/manufacturer/attachment/'; case ApiPaths.stock_item_list: return 'stock/'; case ApiPaths.stock_tracking_list: