Implement CompanyDetails page

This commit is contained in:
Oliver 2024-03-01 01:37:35 +00:00
parent 64109a7974
commit b674fc980d
3 changed files with 120 additions and 4 deletions

View File

@ -5,6 +5,7 @@ import {
IconBox,
IconBuilding,
IconBuildingFactory2,
IconBuildingStore,
IconCalendar,
IconCalendarStats,
IconCheck,
@ -22,6 +23,7 @@ import {
IconLink,
IconList,
IconListTree,
IconMail,
IconMapPin,
IconMapPinHeart,
IconNotes,
@ -30,6 +32,7 @@ import {
IconPackageImport,
IconPackages,
IconPaperclip,
IconPhone,
IconPhoto,
IconProgressCheck,
IconQuestionMark,
@ -49,6 +52,7 @@ import {
IconUserStar,
IconUsersGroup,
IconVersions,
IconWorld,
IconWorldCode,
IconX
} from '@tabler/icons-react';
@ -87,6 +91,7 @@ const icons: { [key: string]: (props: TablerIconsProps) => React.JSX.Element } =
used_in: IconStack2,
manufacturers: IconBuildingFactory2,
suppliers: IconBuilding,
customers: IconBuildingStore,
purchase_orders: IconShoppingCart,
sales_orders: IconTruckDelivery,
scheduling: IconCalendarStats,
@ -121,6 +126,7 @@ const icons: { [key: string]: (props: TablerIconsProps) => React.JSX.Element } =
link: IconLink,
responsible: IconUserStar,
pricing: IconCurrencyDollar,
currency: IconCurrencyDollar,
stocktake: IconClipboardList,
user: IconUser,
group: IconUsersGroup,
@ -128,7 +134,10 @@ const icons: { [key: string]: (props: TablerIconsProps) => React.JSX.Element } =
copy: IconCopy,
quantity: IconNumbers,
progress: IconProgressCheck,
reference: IconHash
reference: IconHash,
website: IconWorld,
email: IconMail,
phone: IconPhone
};
/**

View File

@ -1,5 +1,5 @@
import { t } from '@lingui/macro';
import { LoadingOverlay, Skeleton, Stack } from '@mantine/core';
import { Grid, LoadingOverlay, Skeleton, Stack } from '@mantine/core';
import {
IconBuildingFactory2,
IconBuildingWarehouse,
@ -18,6 +18,8 @@ import {
import { useMemo } from 'react';
import { useParams } from 'react-router-dom';
import { DetailsImage } from '../../components/details/DetailsImage';
import { ItemDetailsGrid } from '../../components/details/ItemDetails';
import {
ActionDropdown,
DeleteItemAction,
@ -35,6 +37,7 @@ import { useEditApiFormModal } from '../../hooks/UseForm';
import { useInstance } from '../../hooks/UseInstance';
import { apiUrl } from '../../states/ApiState';
import { useUserState } from '../../states/UserState';
import { DetailsField, DetailsTable } from '../../tables/Details';
import { AddressTable } from '../../tables/company/AddressTable';
import { ContactTable } from '../../tables/company/ContactTable';
import { AttachmentTable } from '../../tables/general/AttachmentTable';
@ -69,12 +72,99 @@ export default function CompanyDetail(props: CompanyDetailProps) {
refetchOnMount: true
});
const detailsPanel = useMemo(() => {
if (instanceQuery.isFetching) {
return <Skeleton />;
}
let tl: DetailsField[] = [
{
type: 'text',
name: 'description',
label: t`Description`
},
{
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
}
];
let 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>
<Grid>
<Grid.Col span={4}>
<DetailsImage
appRole={UserRoles.purchase_order}
apiPath={ApiEndpoints.company_list}
src={company.image}
pk={company.pk}
refresh={refreshInstance}
imageActions={{
uploadFile: true,
deleteFile: true
}}
/>
</Grid.Col>
<Grid.Col span={8}>
<DetailsTable item={company} fields={tl} />
</Grid.Col>
</Grid>
<DetailsTable item={company} fields={tr} />
</ItemDetailsGrid>
);
}, [company, instanceQuery]);
const companyPanels: PanelType[] = useMemo(() => {
return [
{
name: 'details',
label: t`Details`,
icon: <IconInfoCircle />
icon: <IconInfoCircle />,
content: detailsPanel
},
{
name: 'manufactured-parts',

View File

@ -16,6 +16,7 @@ import { Suspense, useMemo } from 'react';
import { api } from '../App';
import { ProgressBar } from '../components/items/ProgressBar';
import { YesNoButton } from '../components/items/YesNoButton';
import { getModelInfo } from '../components/render/ModelType';
import { StatusRenderer } from '../components/render/StatusRenderer';
import { ApiEndpoints } from '../enums/ApiEndpoints';
@ -45,7 +46,13 @@ export type DetailsField =
badge?: BadgeType;
copy?: boolean;
value_formatter?: () => ValueFormatterReturn;
} & (StringDetailField | LinkDetailField | ProgressBarfield | StatusField);
} & (
| StringDetailField
| BooleanField
| LinkDetailField
| ProgressBarfield
| StatusField
);
type BadgeType = 'owner' | 'user' | 'group';
type ValueFormatterReturn = string | number | null;
@ -55,6 +62,10 @@ type StringDetailField = {
unit?: boolean;
};
type BooleanField = {
type: 'boolean';
};
type LinkDetailField = {
type: 'link';
} & (InternalLinkField | ExternalLinkField);
@ -288,6 +299,10 @@ function TableStringValue(props: FieldProps) {
);
}
function BooleanValue(props: FieldProps) {
return <YesNoButton value={props.field_value} />;
}
function TableAnchorValue(props: FieldProps) {
if (props.field_data.external) {
return (
@ -404,6 +419,8 @@ export function DetailsTableField({
case 'text':
case 'string':
return TableStringValue;
case 'boolean':
return BooleanValue;
case 'link':
return TableAnchorValue;
case 'progressbar':