support Company and BuildOrder
This commit is contained in:
parent
95bf7f709f
commit
dd46cced53
|
|
@ -1,5 +1,7 @@
|
|||
import { ModelType } from '@lib/enums/ModelType';
|
||||
import type { ReactNode } from 'react';
|
||||
import { BuildOrderPreviewComponent } from './models/BuildOrderPreview';
|
||||
import { CompanyPreviewComponent } from './models/CompanyPreview';
|
||||
import { ManufacturerPartPreviewComponent } from './models/ManufacturerPartPreview';
|
||||
import { PartPreviewComponent } from './models/PartPreview';
|
||||
import { PurchaseOrderPreviewComponent } from './models/PurchaseOrderPreview';
|
||||
|
|
@ -43,6 +45,10 @@ export function getPreviewComponentForModel({
|
|||
return SupplierPartPreviewComponent({ instance, modelId });
|
||||
case ModelType.manufacturerpart:
|
||||
return ManufacturerPartPreviewComponent({ instance, modelId });
|
||||
case ModelType.company:
|
||||
return CompanyPreviewComponent({ instance, modelId });
|
||||
case ModelType.build:
|
||||
return BuildOrderPreviewComponent({ instance, modelId });
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
import { t } from '@lingui/core/macro';
|
||||
import { BuildOrderDetailsPanel } from '../../../pages/build/BuildOrderDetailsPanel';
|
||||
import type { PreviewType } from '../PreviewType';
|
||||
|
||||
export function BuildOrderPreviewComponent({
|
||||
instance,
|
||||
modelId
|
||||
}: Readonly<{
|
||||
instance: any;
|
||||
modelId: number;
|
||||
}>): PreviewType {
|
||||
const part = instance?.part_detail?.full_name ?? instance?.part_detail?.name;
|
||||
const ref = instance?.reference ?? `#${modelId}`;
|
||||
|
||||
let title = `${t`Build Order`} ${ref}`;
|
||||
|
||||
if (part) {
|
||||
title += ` (${part})`;
|
||||
}
|
||||
|
||||
return {
|
||||
title,
|
||||
preview: <BuildOrderDetailsPanel instance={instance} />
|
||||
};
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
import { t } from '@lingui/core/macro';
|
||||
import { CompanyDetailsPanel } from '../../../pages/company/CompanyDetailsPanel';
|
||||
import type { PreviewType } from '../PreviewType';
|
||||
|
||||
export function CompanyPreviewComponent({
|
||||
instance,
|
||||
modelId
|
||||
}: Readonly<{
|
||||
instance: any;
|
||||
modelId: number;
|
||||
}>): PreviewType {
|
||||
const name = instance?.name ?? `#${modelId}`;
|
||||
|
||||
return {
|
||||
title: `${t`Company`} - ${name}`,
|
||||
preview: <CompanyDetailsPanel instance={instance} />
|
||||
};
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { t } from '@lingui/core/macro';
|
||||
import { Alert, Grid, Skeleton, Stack, Text } from '@mantine/core';
|
||||
import { Alert, Skeleton, Stack, Text } from '@mantine/core';
|
||||
import {
|
||||
IconChecklist,
|
||||
IconCircleCheck,
|
||||
|
|
@ -21,19 +21,12 @@ import { ModelType } from '@lib/enums/ModelType';
|
|||
import { UserRoles } from '@lib/enums/Roles';
|
||||
import { apiUrl } from '@lib/functions/Api';
|
||||
import { getDetailUrl } from '@lib/functions/Navigation';
|
||||
import { TagsList } from '@lib/index';
|
||||
import type { ApiFormFieldSet } from '@lib/types/Forms';
|
||||
import type { PanelType } from '@lib/types/Panel';
|
||||
import AdminButton from '../../components/buttons/AdminButton';
|
||||
import PrimaryActionButton from '../../components/buttons/PrimaryActionButton';
|
||||
import { PrintingActions } from '../../components/buttons/PrintingActions';
|
||||
import {
|
||||
type DetailsField,
|
||||
DetailsTable
|
||||
} from '../../components/details/Details';
|
||||
import DetailsBadge from '../../components/details/DetailsBadge';
|
||||
import { DetailsImage } from '../../components/details/DetailsImage';
|
||||
import { ItemDetailsGrid } from '../../components/details/ItemDetails';
|
||||
import {
|
||||
BarcodeActionDropdown,
|
||||
CancelItemAction,
|
||||
|
|
@ -66,6 +59,7 @@ import BuildOutputTable from '../../tables/build/BuildOutputTable';
|
|||
import PartTestResultTable from '../../tables/part/PartTestResultTable';
|
||||
import { PurchaseOrderTable } from '../../tables/purchasing/PurchaseOrderTable';
|
||||
import { StockItemTable } from '../../tables/stock/StockItemTable';
|
||||
import { BuildOrderDetailsPanel } from './BuildOrderDetailsPanel';
|
||||
|
||||
function NoItems() {
|
||||
return (
|
||||
|
|
@ -235,242 +229,19 @@ export default function BuildDetail() {
|
|||
refetchOnMount: true
|
||||
});
|
||||
|
||||
const { instance: partRequirements, instanceQuery: partRequirementsQuery } =
|
||||
useInstance({
|
||||
endpoint: ApiEndpoints.part_requirements,
|
||||
pk: build?.part,
|
||||
hasPrimaryKey: true,
|
||||
defaultValue: {}
|
||||
});
|
||||
|
||||
const detailsPanel = useMemo(() => {
|
||||
if (instanceQuery.isFetching) {
|
||||
return <Skeleton />;
|
||||
}
|
||||
|
||||
const data = {
|
||||
...build,
|
||||
can_build: partRequirements?.can_build ?? 0
|
||||
};
|
||||
|
||||
const tl: DetailsField[] = [
|
||||
{
|
||||
type: 'link',
|
||||
name: 'part',
|
||||
label: t`Part`,
|
||||
model: ModelType.part
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'part_detail.IPN',
|
||||
icon: 'part',
|
||||
label: t`IPN`,
|
||||
hidden: !build.part_detail?.IPN,
|
||||
copy: true
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'part_detail.revision',
|
||||
icon: 'revision',
|
||||
label: t`Revision`,
|
||||
hidden: !build.part_detail?.revision,
|
||||
copy: true
|
||||
},
|
||||
{
|
||||
type: 'status',
|
||||
name: 'status',
|
||||
label: t`Status`,
|
||||
model: ModelType.build
|
||||
},
|
||||
{
|
||||
type: 'status',
|
||||
name: 'status_custom_key',
|
||||
label: t`Custom Status`,
|
||||
model: ModelType.build,
|
||||
icon: 'status',
|
||||
hidden:
|
||||
!build.status_custom_key || build.status_custom_key == build.status
|
||||
},
|
||||
{
|
||||
type: 'boolean',
|
||||
name: 'external',
|
||||
label: t`External`,
|
||||
icon: 'manufacturers',
|
||||
hidden: !build.external
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'reference',
|
||||
label: t`Reference`,
|
||||
copy: true
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'title',
|
||||
label: t`Description`,
|
||||
icon: 'description',
|
||||
copy: true
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
name: 'parent',
|
||||
icon: 'builds',
|
||||
label: t`Parent Build`,
|
||||
model_field: 'reference',
|
||||
model: ModelType.build,
|
||||
hidden: !build.parent
|
||||
}
|
||||
];
|
||||
|
||||
const tr: DetailsField[] = [
|
||||
{
|
||||
type: 'number',
|
||||
name: 'quantity',
|
||||
label: t`Build Quantity`
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
name: 'can_build',
|
||||
unit: build.part_detail?.units,
|
||||
label: t`Can Build`,
|
||||
hidden: partRequirements?.can_build === undefined
|
||||
},
|
||||
{
|
||||
type: 'progressbar',
|
||||
name: 'completed',
|
||||
icon: 'progress',
|
||||
total: build.quantity,
|
||||
progress: build.completed,
|
||||
label: t`Completed Outputs`
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
name: 'sales_order',
|
||||
label: t`Sales Order`,
|
||||
icon: 'sales_orders',
|
||||
model: ModelType.salesorder,
|
||||
model_field: 'reference',
|
||||
hidden: !build.sales_order
|
||||
}
|
||||
];
|
||||
|
||||
const bl: DetailsField[] = [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'issued_by',
|
||||
label: t`Issued By`,
|
||||
icon: 'user',
|
||||
badge: 'user',
|
||||
hidden: !build.issued_by
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'responsible',
|
||||
label: t`Responsible`,
|
||||
badge: 'owner',
|
||||
hidden: !build.responsible
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'project_code_label',
|
||||
label: t`Project Code`,
|
||||
icon: 'reference',
|
||||
copy: true,
|
||||
hidden: !build.project_code
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
name: 'take_from',
|
||||
icon: 'location',
|
||||
model: ModelType.stocklocation,
|
||||
label: t`Source Location`,
|
||||
backup_value: t`Any location`
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
name: 'destination',
|
||||
icon: 'location',
|
||||
model: ModelType.stocklocation,
|
||||
label: t`Destination Location`,
|
||||
hidden: !build.destination
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'batch',
|
||||
label: t`Batch Code`,
|
||||
hidden: !build.batch,
|
||||
copy: true
|
||||
}
|
||||
];
|
||||
|
||||
const br: DetailsField[] = [
|
||||
{
|
||||
type: 'date',
|
||||
name: 'creation_date',
|
||||
label: t`Created`,
|
||||
icon: 'calendar',
|
||||
copy: true,
|
||||
hidden: !build.creation_date
|
||||
},
|
||||
{
|
||||
type: 'date',
|
||||
name: 'start_date',
|
||||
label: t`Start Date`,
|
||||
icon: 'calendar',
|
||||
copy: true,
|
||||
hidden: !build.start_date
|
||||
},
|
||||
{
|
||||
type: 'date',
|
||||
name: 'target_date',
|
||||
label: t`Target Date`,
|
||||
icon: 'calendar',
|
||||
copy: true,
|
||||
hidden: !build.target_date
|
||||
},
|
||||
{
|
||||
type: 'date',
|
||||
name: 'completion_date',
|
||||
label: t`Completed`,
|
||||
icon: 'calendar',
|
||||
copy: true,
|
||||
hidden: !build.completion_date
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<ItemDetailsGrid
|
||||
tables={[
|
||||
{ fields: tr, item: data },
|
||||
{ fields: bl, item: data },
|
||||
{ fields: br, item: data }
|
||||
]}
|
||||
>
|
||||
<Stack gap='xs'>
|
||||
<Grid grow>
|
||||
<DetailsImage
|
||||
appRole={UserRoles.part}
|
||||
apiPath={ApiEndpoints.part_list}
|
||||
src={build.part_detail?.image ?? build.part_detail?.thumbnail}
|
||||
pk={build.part}
|
||||
/>
|
||||
<Grid.Col span={{ base: 12, sm: 8 }}>
|
||||
<DetailsTable fields={tl} item={data} />
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
<TagsList tags={build.tags} />
|
||||
</Stack>
|
||||
</ItemDetailsGrid>
|
||||
);
|
||||
}, [build, instanceQuery, partRequirements, partRequirementsQuery]);
|
||||
|
||||
const buildPanels: PanelType[] = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
name: 'details',
|
||||
label: t`Build Details`,
|
||||
icon: <IconInfoCircle />,
|
||||
content: detailsPanel
|
||||
content: (
|
||||
<BuildOrderDetailsPanel
|
||||
instance={build}
|
||||
allowImageEdit
|
||||
refreshInstance={refreshInstance}
|
||||
/>
|
||||
)
|
||||
},
|
||||
{
|
||||
name: 'line-items',
|
||||
|
|
@ -600,7 +371,7 @@ export default function BuildDetail() {
|
|||
build,
|
||||
id,
|
||||
user,
|
||||
partRequirements,
|
||||
|
||||
buildStatus,
|
||||
globalSettings,
|
||||
showChildBuilds,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,262 @@
|
|||
import { t } from '@lingui/core/macro';
|
||||
import { Grid, Skeleton, Stack } from '@mantine/core';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
||||
import { ModelType } from '@lib/enums/ModelType';
|
||||
import { UserRoles } from '@lib/enums/Roles';
|
||||
import { apiUrl } from '@lib/functions/Api';
|
||||
import { TagsList } from '@lib/index';
|
||||
|
||||
import {
|
||||
type DetailsField,
|
||||
DetailsTable
|
||||
} from '../../components/details/Details';
|
||||
import { DetailsImage } from '../../components/details/DetailsImage';
|
||||
import { ItemDetailsGrid } from '../../components/details/ItemDetails';
|
||||
import { useParameterDetailsGrid } from '../../components/details/ParameterDetailsGrid';
|
||||
import { useInstance } from '../../hooks/UseInstance';
|
||||
|
||||
export function BuildOrderDetailsPanel({
|
||||
instance,
|
||||
allowImageEdit = false,
|
||||
refreshInstance
|
||||
}: Readonly<{
|
||||
instance: any;
|
||||
allowImageEdit?: boolean;
|
||||
refreshInstance?: () => void;
|
||||
}>) {
|
||||
const { instance: partRequirements } = useInstance({
|
||||
endpoint: ApiEndpoints.part_requirements,
|
||||
pk: instance?.part,
|
||||
hasPrimaryKey: true,
|
||||
defaultValue: {}
|
||||
});
|
||||
|
||||
const data = useMemo(
|
||||
() => ({ ...instance, can_build: partRequirements?.can_build ?? 0 }),
|
||||
[instance, partRequirements]
|
||||
);
|
||||
|
||||
const tl: DetailsField[] = [
|
||||
{
|
||||
type: 'link',
|
||||
name: 'part',
|
||||
label: t`Part`,
|
||||
model: ModelType.part
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'part_detail.IPN',
|
||||
icon: 'part',
|
||||
label: t`IPN`,
|
||||
hidden: !instance?.part_detail?.IPN,
|
||||
copy: true
|
||||
},
|
||||
{
|
||||
type: 'string',
|
||||
name: 'part_detail.revision',
|
||||
icon: 'revision',
|
||||
label: t`Revision`,
|
||||
hidden: !instance?.part_detail?.revision,
|
||||
copy: true
|
||||
},
|
||||
{
|
||||
type: 'status',
|
||||
name: 'status',
|
||||
label: t`Status`,
|
||||
model: ModelType.build
|
||||
},
|
||||
{
|
||||
type: 'status',
|
||||
name: 'status_custom_key',
|
||||
label: t`Custom Status`,
|
||||
model: ModelType.build,
|
||||
icon: 'status',
|
||||
hidden:
|
||||
!instance?.status_custom_key ||
|
||||
instance?.status_custom_key == instance?.status
|
||||
},
|
||||
{
|
||||
type: 'boolean',
|
||||
name: 'external',
|
||||
label: t`External`,
|
||||
icon: 'manufacturers',
|
||||
hidden: !instance?.external
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'reference',
|
||||
label: t`Reference`,
|
||||
copy: true
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'title',
|
||||
label: t`Description`,
|
||||
icon: 'description',
|
||||
copy: true
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
name: 'parent',
|
||||
icon: 'builds',
|
||||
label: t`Parent Build`,
|
||||
model_field: 'reference',
|
||||
model: ModelType.build,
|
||||
hidden: !instance?.parent
|
||||
}
|
||||
];
|
||||
|
||||
const tr: DetailsField[] = [
|
||||
{
|
||||
type: 'number',
|
||||
name: 'quantity',
|
||||
label: t`Build Quantity`
|
||||
},
|
||||
{
|
||||
type: 'number',
|
||||
name: 'can_build',
|
||||
unit: instance?.part_detail?.units,
|
||||
label: t`Can Build`,
|
||||
hidden: partRequirements?.can_build === undefined
|
||||
},
|
||||
{
|
||||
type: 'progressbar',
|
||||
name: 'completed',
|
||||
icon: 'progress',
|
||||
total: instance?.quantity,
|
||||
progress: instance?.completed,
|
||||
label: t`Completed Outputs`
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
name: 'sales_order',
|
||||
label: t`Sales Order`,
|
||||
icon: 'sales_orders',
|
||||
model: ModelType.salesorder,
|
||||
model_field: 'reference',
|
||||
hidden: !instance?.sales_order
|
||||
}
|
||||
];
|
||||
|
||||
const bl: DetailsField[] = [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'issued_by',
|
||||
label: t`Issued By`,
|
||||
icon: 'user',
|
||||
badge: 'user',
|
||||
hidden: !instance?.issued_by
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'responsible',
|
||||
label: t`Responsible`,
|
||||
badge: 'owner',
|
||||
hidden: !instance?.responsible
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'project_code_label',
|
||||
label: t`Project Code`,
|
||||
icon: 'reference',
|
||||
copy: true,
|
||||
hidden: !instance?.project_code
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
name: 'take_from',
|
||||
icon: 'location',
|
||||
model: ModelType.stocklocation,
|
||||
label: t`Source Location`,
|
||||
backup_value: t`Any location`
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
name: 'destination',
|
||||
icon: 'location',
|
||||
model: ModelType.stocklocation,
|
||||
label: t`Destination Location`,
|
||||
hidden: !instance?.destination
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'batch',
|
||||
label: t`Batch Code`,
|
||||
hidden: !instance?.batch,
|
||||
copy: true
|
||||
}
|
||||
];
|
||||
|
||||
const br: DetailsField[] = [
|
||||
{
|
||||
type: 'date',
|
||||
name: 'creation_date',
|
||||
label: t`Created`,
|
||||
icon: 'calendar',
|
||||
copy: true,
|
||||
hidden: !instance?.creation_date
|
||||
},
|
||||
{
|
||||
type: 'date',
|
||||
name: 'start_date',
|
||||
label: t`Start Date`,
|
||||
icon: 'calendar',
|
||||
copy: true,
|
||||
hidden: !instance?.start_date
|
||||
},
|
||||
{
|
||||
type: 'date',
|
||||
name: 'target_date',
|
||||
label: t`Target Date`,
|
||||
icon: 'calendar',
|
||||
copy: true,
|
||||
hidden: !instance?.target_date
|
||||
},
|
||||
{
|
||||
type: 'date',
|
||||
name: 'completion_date',
|
||||
label: t`Completed`,
|
||||
icon: 'calendar',
|
||||
copy: true,
|
||||
hidden: !instance?.completion_date
|
||||
}
|
||||
];
|
||||
|
||||
const parametersTable = useParameterDetailsGrid({
|
||||
model_type: ModelType.build,
|
||||
model_id: instance?.pk
|
||||
});
|
||||
|
||||
if (!instance?.pk) return <Skeleton />;
|
||||
|
||||
return (
|
||||
<ItemDetailsGrid
|
||||
tables={[
|
||||
{ fields: tr, item: data },
|
||||
{ fields: bl, item: data },
|
||||
{ fields: br, item: data },
|
||||
parametersTable
|
||||
]}
|
||||
>
|
||||
<Stack gap='xs'>
|
||||
<Grid grow>
|
||||
<DetailsImage
|
||||
appRole={allowImageEdit ? UserRoles.part : undefined}
|
||||
apiPath={apiUrl(ApiEndpoints.part_list, instance?.part)}
|
||||
src={
|
||||
instance?.part_detail?.image ?? instance?.part_detail?.thumbnail
|
||||
}
|
||||
pk={instance?.part}
|
||||
refresh={refreshInstance}
|
||||
/>
|
||||
<Grid.Col span={{ base: 12, sm: 8 }}>
|
||||
<DetailsTable fields={tl} item={data} />
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
<TagsList tags={instance?.tags} />
|
||||
</Stack>
|
||||
</ItemDetailsGrid>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import { t } from '@lingui/core/macro';
|
||||
import { Grid, Skeleton, Stack } from '@mantine/core';
|
||||
import { Skeleton, Stack } from '@mantine/core';
|
||||
import {
|
||||
IconBuildingWarehouse,
|
||||
IconInfoCircle,
|
||||
|
|
@ -17,18 +17,10 @@ import { useNavigate, useParams } from 'react-router-dom';
|
|||
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
||||
import { ModelType } from '@lib/enums/ModelType';
|
||||
import { UserRoles } from '@lib/enums/Roles';
|
||||
import { apiUrl } from '@lib/functions/Api';
|
||||
import { TagsList } from '@lib/index';
|
||||
import type { PanelType } from '@lib/types/Panel';
|
||||
import AdminButton from '../../components/buttons/AdminButton';
|
||||
import { PrintingActions } from '../../components/buttons/PrintingActions';
|
||||
import {
|
||||
type DetailsField,
|
||||
DetailsTable
|
||||
} from '../../components/details/Details';
|
||||
import DetailsBadge from '../../components/details/DetailsBadge';
|
||||
import { DetailsImage } from '../../components/details/DetailsImage';
|
||||
import { ItemDetailsGrid } from '../../components/details/ItemDetails';
|
||||
import {
|
||||
DeleteItemAction,
|
||||
EditItemAction,
|
||||
|
|
@ -56,6 +48,7 @@ import { SupplierPartTable } from '../../tables/purchasing/SupplierPartTable';
|
|||
import { ReturnOrderTable } from '../../tables/sales/ReturnOrderTable';
|
||||
import { SalesOrderTable } from '../../tables/sales/SalesOrderTable';
|
||||
import { StockItemTable } from '../../tables/stock/StockItemTable';
|
||||
import { CompanyDetailsPanel } from './CompanyDetailsPanel';
|
||||
|
||||
export type CompanyDetailProps = {
|
||||
title: string;
|
||||
|
|
@ -85,100 +78,15 @@ export default function CompanyDetail(props: Readonly<CompanyDetailProps>) {
|
|||
refetchOnMount: true
|
||||
});
|
||||
|
||||
const detailsPanel = useMemo(() => {
|
||||
if (instanceQuery.isFetching) {
|
||||
return <Skeleton />;
|
||||
}
|
||||
|
||||
const tl: DetailsField[] = [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'description',
|
||||
label: t`Description`,
|
||||
copy: true
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
name: 'website',
|
||||
label: t`Website`,
|
||||
external: true,
|
||||
copy: true,
|
||||
hidden: !company.website
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'phone',
|
||||
label: t`Phone Number`,
|
||||
copy: true,
|
||||
hidden: !company.phone
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'email',
|
||||
label: t`Email Address`,
|
||||
copy: true,
|
||||
hidden: !company.email
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'tax_id',
|
||||
label: t`Tax ID`,
|
||||
copy: true,
|
||||
hidden: !company.tax_id
|
||||
}
|
||||
];
|
||||
|
||||
const tr: DetailsField[] = [
|
||||
{
|
||||
type: 'string',
|
||||
name: 'currency',
|
||||
label: t`Default Currency`
|
||||
},
|
||||
{
|
||||
type: 'boolean',
|
||||
name: 'is_supplier',
|
||||
label: t`Supplier`,
|
||||
icon: 'suppliers'
|
||||
},
|
||||
{
|
||||
type: 'boolean',
|
||||
name: 'is_manufacturer',
|
||||
label: t`Manufacturer`,
|
||||
icon: 'manufacturers'
|
||||
},
|
||||
{
|
||||
type: 'boolean',
|
||||
name: 'is_customer',
|
||||
label: t`Customer`,
|
||||
icon: 'customers'
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<ItemDetailsGrid tables={[{ item: company, fields: tr }]}>
|
||||
<Stack gap='xs'>
|
||||
<Grid grow>
|
||||
<DetailsImage
|
||||
appRole={UserRoles.purchase_order}
|
||||
apiPath={apiUrl(ApiEndpoints.company_list, company.pk)}
|
||||
src={company.image}
|
||||
pk={company.pk}
|
||||
refresh={refreshInstance}
|
||||
imageActions={{
|
||||
uploadFile: true,
|
||||
downloadImage: true,
|
||||
deleteFile: true
|
||||
}}
|
||||
/>
|
||||
<Grid.Col span={{ base: 12, sm: 8 }}>
|
||||
<DetailsTable item={company} fields={tl} />
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
<TagsList tags={company.tags} />
|
||||
</Stack>
|
||||
</ItemDetailsGrid>
|
||||
);
|
||||
}, [company, instanceQuery]);
|
||||
const detailsPanel = instanceQuery.isFetching ? (
|
||||
<Skeleton />
|
||||
) : (
|
||||
<CompanyDetailsPanel
|
||||
instance={company}
|
||||
allowImageEdit
|
||||
refreshInstance={refreshInstance}
|
||||
/>
|
||||
);
|
||||
|
||||
const companyPanels: PanelType[] = useMemo(() => {
|
||||
return [
|
||||
|
|
|
|||
|
|
@ -0,0 +1,119 @@
|
|||
import { t } from '@lingui/core/macro';
|
||||
import { Grid, Skeleton, Stack } from '@mantine/core';
|
||||
|
||||
import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
||||
import { UserRoles } from '@lib/enums/Roles';
|
||||
import { apiUrl } from '@lib/functions/Api';
|
||||
import { TagsList } from '@lib/index';
|
||||
|
||||
import {
|
||||
type DetailsField,
|
||||
DetailsTable
|
||||
} from '../../components/details/Details';
|
||||
import { DetailsImage } from '../../components/details/DetailsImage';
|
||||
import { ItemDetailsGrid } from '../../components/details/ItemDetails';
|
||||
|
||||
export function CompanyDetailsPanel({
|
||||
instance,
|
||||
allowImageEdit = false,
|
||||
refreshInstance
|
||||
}: Readonly<{
|
||||
instance: any;
|
||||
allowImageEdit?: boolean;
|
||||
refreshInstance?: () => void;
|
||||
}>) {
|
||||
const tl: DetailsField[] = [
|
||||
{
|
||||
type: 'text',
|
||||
name: 'description',
|
||||
label: t`Description`,
|
||||
copy: true
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
name: 'website',
|
||||
label: t`Website`,
|
||||
external: true,
|
||||
copy: true,
|
||||
hidden: !instance?.website
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'phone',
|
||||
label: t`Phone Number`,
|
||||
copy: true,
|
||||
hidden: !instance?.phone
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'email',
|
||||
label: t`Email Address`,
|
||||
copy: true,
|
||||
hidden: !instance?.email
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
name: 'tax_id',
|
||||
label: t`Tax ID`,
|
||||
copy: true,
|
||||
hidden: !instance?.tax_id
|
||||
}
|
||||
];
|
||||
|
||||
const tr: DetailsField[] = [
|
||||
{
|
||||
type: 'string',
|
||||
name: 'currency',
|
||||
label: t`Default Currency`
|
||||
},
|
||||
{
|
||||
type: 'boolean',
|
||||
name: 'is_supplier',
|
||||
label: t`Supplier`,
|
||||
icon: 'suppliers'
|
||||
},
|
||||
{
|
||||
type: 'boolean',
|
||||
name: 'is_manufacturer',
|
||||
label: t`Manufacturer`,
|
||||
icon: 'manufacturers'
|
||||
},
|
||||
{
|
||||
type: 'boolean',
|
||||
name: 'is_customer',
|
||||
label: t`Customer`,
|
||||
icon: 'customers'
|
||||
}
|
||||
];
|
||||
|
||||
if (!instance?.pk) return <Skeleton />;
|
||||
|
||||
return (
|
||||
<ItemDetailsGrid tables={[{ item: instance, fields: tr }]}>
|
||||
<Stack gap='xs'>
|
||||
<Grid grow>
|
||||
<DetailsImage
|
||||
appRole={allowImageEdit ? UserRoles.purchase_order : undefined}
|
||||
apiPath={apiUrl(ApiEndpoints.company_list, instance.pk)}
|
||||
src={instance.image}
|
||||
pk={instance.pk}
|
||||
refresh={refreshInstance}
|
||||
imageActions={
|
||||
allowImageEdit
|
||||
? {
|
||||
uploadFile: true,
|
||||
downloadImage: true,
|
||||
deleteFile: true
|
||||
}
|
||||
: {}
|
||||
}
|
||||
/>
|
||||
<Grid.Col span={{ base: 12, sm: 8 }}>
|
||||
<DetailsTable item={instance} fields={tl} />
|
||||
</Grid.Col>
|
||||
</Grid>
|
||||
<TagsList tags={instance.tags} />
|
||||
</Stack>
|
||||
</ItemDetailsGrid>
|
||||
);
|
||||
}
|
||||
|
|
@ -8,7 +8,7 @@ import { ApiEndpoints } from '@lib/enums/ApiEndpoints';
|
|||
import { ModelType } from '@lib/enums/ModelType';
|
||||
import { UserRoles } from '@lib/enums/Roles';
|
||||
import { apiUrl } from '@lib/functions/Api';
|
||||
import { navigateToLink } from '@lib/functions/Navigation';
|
||||
import { eventModified, navigateToLink } from '@lib/functions/Navigation';
|
||||
import useTable from '@lib/hooks/UseTable';
|
||||
import type { TableFilter } from '@lib/types/Filters';
|
||||
import { companyFields } from '../../forms/CompanyForms';
|
||||
|
|
@ -16,6 +16,7 @@ import {
|
|||
useCreateApiFormModal,
|
||||
useEditApiFormModal
|
||||
} from '../../hooks/UseForm';
|
||||
import { usePreviewDrawerState } from '../../states/PreviewDrawerState';
|
||||
import { useUserState } from '../../states/UserState';
|
||||
import {
|
||||
BooleanColumn,
|
||||
|
|
@ -49,6 +50,7 @@ export function CompanyTable({
|
|||
|
||||
const navigate = useNavigate();
|
||||
const user = useUserState();
|
||||
const previewDrawer = usePreviewDrawerState();
|
||||
|
||||
const columns = useMemo(() => {
|
||||
return [
|
||||
|
|
@ -166,10 +168,16 @@ export function CompanyTable({
|
|||
params: {
|
||||
...params
|
||||
},
|
||||
onRowClick: (record: any, index: number, event: any) => {
|
||||
if (record.pk) {
|
||||
const base = path ?? 'company';
|
||||
navigateToLink(`/${base}/${record.pk}`, navigate, event);
|
||||
onRowClick: (record: any, _index: number, event: any) => {
|
||||
if (!record.pk) return;
|
||||
if (eventModified(event as any)) {
|
||||
navigateToLink(
|
||||
`/${path ?? 'company'}/${record.pk}`,
|
||||
navigate,
|
||||
event
|
||||
);
|
||||
} else {
|
||||
previewDrawer.openPreview(ModelType.company, Number(record.pk));
|
||||
}
|
||||
},
|
||||
modelType: ModelType.company,
|
||||
|
|
|
|||
Loading…
Reference in New Issue