feat: deal attributes editing
This commit is contained in:
@ -32,7 +32,7 @@
|
||||
"clsx": "^2.1.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"date-fns-tz": "^3.2.0",
|
||||
"dayjs": "^1.11.15",
|
||||
"dayjs": "^1.11.18",
|
||||
"framer-motion": "^12.23.7",
|
||||
"handlebars": "^4.7.8",
|
||||
"i18n-iso-countries": "^7.14.0",
|
||||
|
||||
@ -0,0 +1,101 @@
|
||||
import { CSSProperties, FC, JSX } from "react";
|
||||
import { Checkbox, NumberInput, TextInput } from "@mantine/core";
|
||||
import { DatePickerInput, DateTimePicker } from "@mantine/dates";
|
||||
import { DealModuleAttributeSchema } from "@/lib/client";
|
||||
import { naiveDateTimeStringToUtc } from "@/utils/datetime";
|
||||
|
||||
type Props = {
|
||||
attrInfo: DealModuleAttributeSchema;
|
||||
value: any;
|
||||
onChange: (value: any) => void;
|
||||
error?: string;
|
||||
style?: CSSProperties;
|
||||
};
|
||||
|
||||
const AttributeValueInput: FC<Props> = ({
|
||||
attrInfo,
|
||||
value,
|
||||
onChange,
|
||||
error,
|
||||
style,
|
||||
}) => {
|
||||
const commonProps = {
|
||||
label: attrInfo.label,
|
||||
style,
|
||||
error,
|
||||
};
|
||||
|
||||
const renderCheckbox = () => {
|
||||
const localValue = value === undefined ? false : value;
|
||||
return (
|
||||
<Checkbox
|
||||
{...commonProps}
|
||||
checked={localValue}
|
||||
onChange={e => onChange(e.currentTarget.checked)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const renderDatePicker = () => (
|
||||
<DatePickerInput
|
||||
{...commonProps}
|
||||
value={value ? new Date(String(value)) : null}
|
||||
onChange={val => {
|
||||
onChange(val ? new Date(val) : null);
|
||||
}}
|
||||
clearable
|
||||
locale={"ru"}
|
||||
valueFormat={"DD.MM.YYYY"}
|
||||
/>
|
||||
);
|
||||
|
||||
const renderDateTimePicker = () => (
|
||||
<DateTimePicker
|
||||
{...commonProps}
|
||||
value={value ? naiveDateTimeStringToUtc(value) : null}
|
||||
onChange={val => {
|
||||
if (!val) return;
|
||||
const localDate = new Date(val.replace(" ", "T"));
|
||||
const utcString = localDate
|
||||
.toISOString()
|
||||
.substring(0, 19)
|
||||
.replace("T", " ");
|
||||
onChange(utcString);
|
||||
}}
|
||||
clearable
|
||||
locale={"ru"}
|
||||
valueFormat={"DD.MM.YYYY HH:mm"}
|
||||
/>
|
||||
);
|
||||
|
||||
const renderTextInput = () => (
|
||||
<TextInput
|
||||
{...commonProps}
|
||||
value={value ?? ""}
|
||||
onChange={e => onChange(e.currentTarget.value)}
|
||||
/>
|
||||
);
|
||||
|
||||
const renderNumberInput = () => (
|
||||
<NumberInput
|
||||
{...commonProps}
|
||||
allowDecimal={attrInfo.type.type === "float"}
|
||||
value={Number(value)}
|
||||
onChange={value => onChange(Number(value))}
|
||||
/>
|
||||
);
|
||||
|
||||
const renderingFuncMap: Record<string, () => JSX.Element> = {
|
||||
bool: renderCheckbox,
|
||||
date: renderDatePicker,
|
||||
datetime: renderDateTimePicker,
|
||||
str: renderTextInput,
|
||||
int: renderNumberInput,
|
||||
float: renderNumberInput,
|
||||
};
|
||||
|
||||
const render = renderingFuncMap[attrInfo.type.type];
|
||||
return render();
|
||||
};
|
||||
|
||||
export default AttributeValueInput;
|
||||
@ -1,8 +1,9 @@
|
||||
import React, { FC, ReactNode } from "react";
|
||||
import { IconEdit, IconHistory } from "@tabler/icons-react";
|
||||
import { motion } from "framer-motion";
|
||||
import { IconBlocks, IconEdit, IconHistory } from "@tabler/icons-react";
|
||||
import { Box, Tabs, Text } from "@mantine/core";
|
||||
import DealEditorTabPanel from "@/app/deals/drawers/DealEditorDrawer/components/DealEditorTabPanel";
|
||||
import TabsList from "@/app/deals/drawers/DealEditorDrawer/components/TabsList";
|
||||
import CustomTab from "@/app/deals/drawers/DealEditorDrawer/tabs/CustomTab/CustomTab";
|
||||
import DealStatusHistoryTab from "@/app/deals/drawers/DealEditorDrawer/tabs/DealStatusHistoryTab/DealStatusHistoryTab";
|
||||
import GeneralTab from "@/app/deals/drawers/DealEditorDrawer/tabs/GeneralTab/GeneralTab";
|
||||
import useIsMobile from "@/hooks/utils/useIsMobile";
|
||||
@ -20,23 +21,6 @@ type Props = {
|
||||
const DealEditorBody: FC<Props> = props => {
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
const getTabPanel = (value: string, component: ReactNode): ReactNode => (
|
||||
<Tabs.Panel
|
||||
key={value}
|
||||
value={value}>
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.2 }}>
|
||||
<Box
|
||||
h={"100%"}
|
||||
w={"100%"}>
|
||||
{component}
|
||||
</Box>
|
||||
</motion.div>
|
||||
</Tabs.Panel>
|
||||
);
|
||||
|
||||
const getTab = (key: string, label: string, icon: ReactNode) => (
|
||||
<Tabs.Tab
|
||||
key={key}
|
||||
@ -56,6 +40,13 @@ const DealEditorBody: FC<Props> = props => {
|
||||
const tabs: ReactNode[] = [];
|
||||
|
||||
for (const module of props.project.modules) {
|
||||
if (!module.isBuiltIn) {
|
||||
for (const tab of module.tabs) {
|
||||
tabs.push(getTab(tab.key, tab.label, <IconBlocks />));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
const moduleInfo = MODULES[module.key];
|
||||
for (const tab of moduleInfo.tabs) {
|
||||
if (
|
||||
@ -76,6 +67,23 @@ const DealEditorBody: FC<Props> = props => {
|
||||
const tabPanels: ReactNode[] = [];
|
||||
|
||||
for (const module of props.project.modules) {
|
||||
if (!module.isBuiltIn) {
|
||||
const tabPanel = (
|
||||
<DealEditorTabPanel
|
||||
key={module.key}
|
||||
value={module.key}>
|
||||
<CustomTab
|
||||
key={module.key}
|
||||
module={module}
|
||||
deal={props.value}
|
||||
/>
|
||||
</DealEditorTabPanel>
|
||||
);
|
||||
|
||||
tabPanels.push(tabPanel);
|
||||
continue;
|
||||
}
|
||||
|
||||
const moduleInfo = MODULES[module.key];
|
||||
for (const tab of moduleInfo.tabs) {
|
||||
if (
|
||||
@ -84,7 +92,14 @@ const DealEditorBody: FC<Props> = props => {
|
||||
)
|
||||
continue;
|
||||
|
||||
tabPanels.push(getTabPanel(tab.key, tab.tab(props)));
|
||||
const tabPanel = (
|
||||
<DealEditorTabPanel
|
||||
key={tab.key}
|
||||
value={tab.key}>
|
||||
{tab.tab(props)}
|
||||
</DealEditorTabPanel>
|
||||
);
|
||||
tabPanels.push(tabPanel);
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,8 +120,12 @@ const DealEditorBody: FC<Props> = props => {
|
||||
{getModuleTabs()}
|
||||
</TabsList>
|
||||
|
||||
{getTabPanel("general", <GeneralTab {...props} />)}
|
||||
{getTabPanel("history", <DealStatusHistoryTab {...props} />)}
|
||||
<DealEditorTabPanel value={"general"}>
|
||||
<GeneralTab {...props} />
|
||||
</DealEditorTabPanel>
|
||||
<DealEditorTabPanel value={"history"}>
|
||||
<DealStatusHistoryTab {...props} />
|
||||
</DealEditorTabPanel>
|
||||
{getModuleTabPanels()}
|
||||
</Tabs>
|
||||
);
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
import React, { FC, PropsWithChildren } from "react";
|
||||
import { motion } from "framer-motion";
|
||||
import { Box, Tabs } from "@mantine/core";
|
||||
|
||||
type Props = {
|
||||
value: string;
|
||||
};
|
||||
|
||||
const DealEditorTabPanel: FC<PropsWithChildren<Props>> = ({
|
||||
value,
|
||||
children,
|
||||
}) => {
|
||||
return (
|
||||
<Tabs.Panel
|
||||
key={value}
|
||||
value={value}>
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ duration: 0.2 }}>
|
||||
<Box
|
||||
h={"100%"}
|
||||
w={"100%"}>
|
||||
{children}
|
||||
</Box>
|
||||
</motion.div>
|
||||
</Tabs.Panel>
|
||||
);
|
||||
};
|
||||
|
||||
export default DealEditorTabPanel;
|
||||
@ -0,0 +1,76 @@
|
||||
import { useMemo } from "react";
|
||||
import { useMutation, useQuery } from "@tanstack/react-query";
|
||||
import { AxiosError } from "axios";
|
||||
import {
|
||||
DealModuleAttributeSchema,
|
||||
HttpValidationError,
|
||||
UpdateDealModuleAttributeSchema,
|
||||
} from "@/lib/client";
|
||||
import {
|
||||
getDealModuleAttributesOptions,
|
||||
updateDealModuleAttributesMutation,
|
||||
} from "@/lib/client/@tanstack/react-query.gen";
|
||||
import { notifications } from "@/lib/notifications";
|
||||
|
||||
type Props = {
|
||||
dealId: number;
|
||||
moduleId: number;
|
||||
};
|
||||
|
||||
const useDealAttributeValuesActions = ({ dealId, moduleId }: Props) => {
|
||||
const { data, refetch: refetchAttributes } = useQuery(
|
||||
getDealModuleAttributesOptions({
|
||||
path: {
|
||||
dealId,
|
||||
moduleId,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
const sortedAttributes = useMemo(() => {
|
||||
if (!data?.attributes) return [];
|
||||
const sortedAttributes: DealModuleAttributeSchema[] = [];
|
||||
for (const attr of data.attributes) {
|
||||
if (attr.type.type === "bool") sortedAttributes.push(attr);
|
||||
else sortedAttributes.unshift(attr);
|
||||
}
|
||||
return sortedAttributes;
|
||||
}, [data?.attributes]);
|
||||
|
||||
const onError = (error: AxiosError<HttpValidationError>) => {
|
||||
console.error(error);
|
||||
notifications.error({
|
||||
message: error.response?.data?.detail as string | undefined,
|
||||
});
|
||||
};
|
||||
|
||||
const updateAttributeValuesMutation = useMutation({
|
||||
...updateDealModuleAttributesMutation(),
|
||||
onError,
|
||||
onSuccess: ({ message }) => {
|
||||
notifications.success({ message });
|
||||
refetchAttributes();
|
||||
},
|
||||
});
|
||||
|
||||
const updateAttributeValues = (
|
||||
attributeValues: UpdateDealModuleAttributeSchema[]
|
||||
) => {
|
||||
updateAttributeValuesMutation.mutate({
|
||||
path: {
|
||||
moduleId,
|
||||
dealId,
|
||||
},
|
||||
body: {
|
||||
attributes: attributeValues,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
dealAttributes: sortedAttributes,
|
||||
updateAttributeValues,
|
||||
};
|
||||
};
|
||||
|
||||
export default useDealAttributeValuesActions;
|
||||
@ -0,0 +1,141 @@
|
||||
import React, {
|
||||
FC,
|
||||
ReactNode,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from "react";
|
||||
import { Flex, Group } from "@mantine/core";
|
||||
import AttributeValueInput from "@/app/deals/drawers/DealEditorDrawer/components/AttributeValueInput";
|
||||
import useDealAttributeValuesActions from "@/app/deals/drawers/DealEditorDrawer/hooks/useDealAttributeValuesActions";
|
||||
import FormFlexRow from "@/components/ui/FormFlexRow/FormFlexRow";
|
||||
import InlineButton from "@/components/ui/InlineButton/InlineButton";
|
||||
import {
|
||||
DealModuleAttributeSchema,
|
||||
DealSchema,
|
||||
ModuleSchemaOutput,
|
||||
UpdateDealModuleAttributeSchema,
|
||||
} from "@/lib/client";
|
||||
|
||||
type Props = {
|
||||
module: ModuleSchemaOutput;
|
||||
deal: DealSchema;
|
||||
};
|
||||
|
||||
type Value = {
|
||||
value?: any;
|
||||
};
|
||||
|
||||
const CustomTab: FC<Props> = ({ module, deal }) => {
|
||||
const { dealAttributes, updateAttributeValues } =
|
||||
useDealAttributeValuesActions({
|
||||
moduleId: module.id,
|
||||
dealId: deal.id,
|
||||
});
|
||||
|
||||
const [attributeValuesMap, setAttributeValuesMap] = useState<
|
||||
Map<number, Value | null>
|
||||
>(new Map());
|
||||
const [attributeErrorsMap, setAttributeErrorsMap] = useState<
|
||||
Map<number, string>
|
||||
>(new Map());
|
||||
|
||||
useEffect(() => {
|
||||
const values = new Map<number, Value | null>();
|
||||
for (const dealAttr of dealAttributes) {
|
||||
values.set(dealAttr.attributeId, dealAttr?.value);
|
||||
}
|
||||
setAttributeValuesMap(values);
|
||||
}, [dealAttributes]);
|
||||
|
||||
const onSubmit = () => {
|
||||
let isErrorFound = false;
|
||||
for (const attr of dealAttributes) {
|
||||
const value = attributeValuesMap.get(attr.attributeId);
|
||||
if (!attr.isNullable && (value === null || value === undefined)) {
|
||||
attributeErrorsMap.set(attr.attributeId, "Обязательное поле");
|
||||
isErrorFound = true;
|
||||
}
|
||||
}
|
||||
setAttributeErrorsMap(new Map(attributeErrorsMap));
|
||||
if (isErrorFound) return;
|
||||
|
||||
const attributeValues: UpdateDealModuleAttributeSchema[] =
|
||||
attributeValuesMap
|
||||
.entries()
|
||||
.map(
|
||||
([attributeId, value]) =>
|
||||
({
|
||||
attributeId,
|
||||
value,
|
||||
}) as UpdateDealModuleAttributeSchema
|
||||
)
|
||||
.toArray();
|
||||
|
||||
updateAttributeValues(attributeValues);
|
||||
};
|
||||
|
||||
const getAttributeElement = useCallback(
|
||||
(attribute: DealModuleAttributeSchema) => (
|
||||
<AttributeValueInput
|
||||
key={attribute.attributeId}
|
||||
attrInfo={attribute}
|
||||
value={attributeValuesMap.get(attribute.attributeId)?.value}
|
||||
onChange={value => {
|
||||
attributeValuesMap.set(attribute.attributeId, { value });
|
||||
setAttributeValuesMap(new Map(attributeValuesMap));
|
||||
attributeErrorsMap.delete(attribute.attributeId);
|
||||
setAttributeErrorsMap(new Map(attributeErrorsMap));
|
||||
}}
|
||||
style={{ flex: 1 }}
|
||||
error={attributeErrorsMap.get(attribute.attributeId)}
|
||||
/>
|
||||
),
|
||||
[attributeValuesMap, attributeErrorsMap]
|
||||
);
|
||||
|
||||
const attributesRows = useMemo(() => {
|
||||
if (!dealAttributes) return [];
|
||||
const boolAttributes = dealAttributes.filter(
|
||||
a => a.type.type === "bool"
|
||||
);
|
||||
const otherAttributes = dealAttributes.filter(
|
||||
a => a.type.type !== "bool"
|
||||
);
|
||||
|
||||
const rows: ReactNode[] = [];
|
||||
for (let i = 0; i < otherAttributes.length; i += 2) {
|
||||
const rightIdx = i + 1;
|
||||
|
||||
rows.push(
|
||||
<FormFlexRow key={`row${i}`}>
|
||||
{getAttributeElement(otherAttributes[i])}
|
||||
{rightIdx < otherAttributes.length &&
|
||||
getAttributeElement(otherAttributes[rightIdx])}
|
||||
</FormFlexRow>
|
||||
);
|
||||
}
|
||||
|
||||
for (const attr of boolAttributes) {
|
||||
rows.push(getAttributeElement(attr));
|
||||
}
|
||||
|
||||
return rows;
|
||||
}, [dealAttributes, getAttributeElement]);
|
||||
|
||||
return (
|
||||
<Flex
|
||||
direction={"column"}
|
||||
gap={"xs"}
|
||||
py={"xs"}
|
||||
px={"md"}>
|
||||
{attributesRows}
|
||||
<Group>
|
||||
<InlineButton onClick={onSubmit}>Сохранить</InlineButton>
|
||||
</Group>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export default CustomTab;
|
||||
@ -59,6 +59,7 @@ import {
|
||||
getBaseMarketplaces,
|
||||
getBoards,
|
||||
getClients,
|
||||
getDealModuleAttributes,
|
||||
getDealProducts,
|
||||
getDeals,
|
||||
getDealServices,
|
||||
@ -85,6 +86,7 @@ import {
|
||||
updateClient,
|
||||
updateDeal,
|
||||
updateDealGroup,
|
||||
updateDealModuleAttributes,
|
||||
updateDealProduct,
|
||||
updateDealProductService,
|
||||
updateDealService,
|
||||
@ -234,6 +236,7 @@ import type {
|
||||
GetBaseMarketplacesData,
|
||||
GetBoardsData,
|
||||
GetClientsData,
|
||||
GetDealModuleAttributesData,
|
||||
GetDealProductsData,
|
||||
GetDealsData,
|
||||
GetDealsError,
|
||||
@ -284,6 +287,9 @@ import type {
|
||||
UpdateDealGroupData,
|
||||
UpdateDealGroupError,
|
||||
UpdateDealGroupResponse2,
|
||||
UpdateDealModuleAttributesData,
|
||||
UpdateDealModuleAttributesError,
|
||||
UpdateDealModuleAttributesResponse2,
|
||||
UpdateDealProductData,
|
||||
UpdateDealProductError,
|
||||
UpdateDealProductResponse2,
|
||||
@ -569,6 +575,81 @@ export const getAttributeTypesOptions = (
|
||||
});
|
||||
};
|
||||
|
||||
export const getDealModuleAttributesQueryKey = (
|
||||
options: Options<GetDealModuleAttributesData>
|
||||
) => createQueryKey("getDealModuleAttributes", options);
|
||||
|
||||
/**
|
||||
* Get Deal Module Attributes
|
||||
*/
|
||||
export const getDealModuleAttributesOptions = (
|
||||
options: Options<GetDealModuleAttributesData>
|
||||
) => {
|
||||
return queryOptions({
|
||||
queryFn: async ({ queryKey, signal }) => {
|
||||
const { data } = await getDealModuleAttributes({
|
||||
...options,
|
||||
...queryKey[0],
|
||||
signal,
|
||||
throwOnError: true,
|
||||
});
|
||||
return data;
|
||||
},
|
||||
queryKey: getDealModuleAttributesQueryKey(options),
|
||||
});
|
||||
};
|
||||
|
||||
export const updateDealModuleAttributesQueryKey = (
|
||||
options: Options<UpdateDealModuleAttributesData>
|
||||
) => createQueryKey("updateDealModuleAttributes", options);
|
||||
|
||||
/**
|
||||
* Update Deal Module Attributes
|
||||
*/
|
||||
export const updateDealModuleAttributesOptions = (
|
||||
options: Options<UpdateDealModuleAttributesData>
|
||||
) => {
|
||||
return queryOptions({
|
||||
queryFn: async ({ queryKey, signal }) => {
|
||||
const { data } = await updateDealModuleAttributes({
|
||||
...options,
|
||||
...queryKey[0],
|
||||
signal,
|
||||
throwOnError: true,
|
||||
});
|
||||
return data;
|
||||
},
|
||||
queryKey: updateDealModuleAttributesQueryKey(options),
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Update Deal Module Attributes
|
||||
*/
|
||||
export const updateDealModuleAttributesMutation = (
|
||||
options?: Partial<Options<UpdateDealModuleAttributesData>>
|
||||
): UseMutationOptions<
|
||||
UpdateDealModuleAttributesResponse2,
|
||||
AxiosError<UpdateDealModuleAttributesError>,
|
||||
Options<UpdateDealModuleAttributesData>
|
||||
> => {
|
||||
const mutationOptions: UseMutationOptions<
|
||||
UpdateDealModuleAttributesResponse2,
|
||||
AxiosError<UpdateDealModuleAttributesError>,
|
||||
Options<UpdateDealModuleAttributesData>
|
||||
> = {
|
||||
mutationFn: async localOptions => {
|
||||
const { data } = await updateDealModuleAttributes({
|
||||
...options,
|
||||
...localOptions,
|
||||
throwOnError: true,
|
||||
});
|
||||
return data;
|
||||
},
|
||||
};
|
||||
return mutationOptions;
|
||||
};
|
||||
|
||||
export const getBoardsQueryKey = (options: Options<GetBoardsData>) =>
|
||||
createQueryKey("getBoards", options);
|
||||
|
||||
|
||||
@ -149,6 +149,9 @@ import type {
|
||||
GetClientsData,
|
||||
GetClientsErrors,
|
||||
GetClientsResponses,
|
||||
GetDealModuleAttributesData,
|
||||
GetDealModuleAttributesErrors,
|
||||
GetDealModuleAttributesResponses,
|
||||
GetDealProductsData,
|
||||
GetDealProductsErrors,
|
||||
GetDealProductsResponses,
|
||||
@ -219,6 +222,9 @@ import type {
|
||||
UpdateDealGroupData,
|
||||
UpdateDealGroupErrors,
|
||||
UpdateDealGroupResponses,
|
||||
UpdateDealModuleAttributesData,
|
||||
UpdateDealModuleAttributesErrors,
|
||||
UpdateDealModuleAttributesResponses,
|
||||
UpdateDealProductData,
|
||||
UpdateDealProductErrors,
|
||||
UpdateDealProductResponses,
|
||||
@ -365,6 +371,8 @@ import {
|
||||
zGetBoardsResponse2,
|
||||
zGetClientsData,
|
||||
zGetClientsResponse2,
|
||||
zGetDealModuleAttributesData,
|
||||
zGetDealModuleAttributesResponse2,
|
||||
zGetDealProductsData,
|
||||
zGetDealProductsResponse2,
|
||||
zGetDealsData,
|
||||
@ -416,6 +424,8 @@ import {
|
||||
zUpdateDealData,
|
||||
zUpdateDealGroupData,
|
||||
zUpdateDealGroupResponse2,
|
||||
zUpdateDealModuleAttributesData,
|
||||
zUpdateDealModuleAttributesResponse2,
|
||||
zUpdateDealProductData,
|
||||
zUpdateDealProductResponse2,
|
||||
zUpdateDealProductServiceData,
|
||||
@ -616,6 +626,58 @@ export const getAttributeTypes = <ThrowOnError extends boolean = false>(
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get Deal Module Attributes
|
||||
*/
|
||||
export const getDealModuleAttributes = <ThrowOnError extends boolean = false>(
|
||||
options: Options<GetDealModuleAttributesData, ThrowOnError>
|
||||
) => {
|
||||
return (options.client ?? _heyApiClient).get<
|
||||
GetDealModuleAttributesResponses,
|
||||
GetDealModuleAttributesErrors,
|
||||
ThrowOnError
|
||||
>({
|
||||
requestValidator: async data => {
|
||||
return await zGetDealModuleAttributesData.parseAsync(data);
|
||||
},
|
||||
responseType: "json",
|
||||
responseValidator: async data => {
|
||||
return await zGetDealModuleAttributesResponse2.parseAsync(data);
|
||||
},
|
||||
url: "/crm/v1/attribute/deal/{dealId}/module/{moduleId}",
|
||||
...options,
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Update Deal Module Attributes
|
||||
*/
|
||||
export const updateDealModuleAttributes = <
|
||||
ThrowOnError extends boolean = false,
|
||||
>(
|
||||
options: Options<UpdateDealModuleAttributesData, ThrowOnError>
|
||||
) => {
|
||||
return (options.client ?? _heyApiClient).post<
|
||||
UpdateDealModuleAttributesResponses,
|
||||
UpdateDealModuleAttributesErrors,
|
||||
ThrowOnError
|
||||
>({
|
||||
requestValidator: async data => {
|
||||
return await zUpdateDealModuleAttributesData.parseAsync(data);
|
||||
},
|
||||
responseType: "json",
|
||||
responseValidator: async data => {
|
||||
return await zUpdateDealModuleAttributesResponse2.parseAsync(data);
|
||||
},
|
||||
url: "/crm/v1/attribute/deal/{dealId}/module/{moduleId}",
|
||||
...options,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
...options.headers,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Get Boards
|
||||
*/
|
||||
|
||||
@ -1034,6 +1034,57 @@ export type DealGroupSchema = {
|
||||
lexorank: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* DealModuleAttributeSchema
|
||||
*/
|
||||
export type DealModuleAttributeSchema = {
|
||||
/**
|
||||
* Attributeid
|
||||
*/
|
||||
attributeId: number;
|
||||
/**
|
||||
* Label
|
||||
*/
|
||||
label: string;
|
||||
/**
|
||||
* Originallabel
|
||||
*/
|
||||
originalLabel: string;
|
||||
/**
|
||||
* Value
|
||||
*/
|
||||
value: {
|
||||
[key: string]: unknown;
|
||||
} | null;
|
||||
type: AttributeTypeSchema;
|
||||
/**
|
||||
* Defaultvalue
|
||||
*/
|
||||
defaultValue: {
|
||||
[key: string]: unknown;
|
||||
};
|
||||
/**
|
||||
* Description
|
||||
*/
|
||||
description: string;
|
||||
/**
|
||||
* Isapplicabletogroup
|
||||
*/
|
||||
isApplicableToGroup: boolean;
|
||||
/**
|
||||
* Isshownondashboard
|
||||
*/
|
||||
isShownOnDashboard: boolean;
|
||||
/**
|
||||
* Ishighlightifexpired
|
||||
*/
|
||||
isHighlightIfExpired: boolean;
|
||||
/**
|
||||
* Isnullable
|
||||
*/
|
||||
isNullable: boolean;
|
||||
};
|
||||
|
||||
/**
|
||||
* DealProductAddKitRequest
|
||||
*/
|
||||
@ -1510,6 +1561,16 @@ export type GetClientsResponse = {
|
||||
items: Array<ClientSchema>;
|
||||
};
|
||||
|
||||
/**
|
||||
* GetDealModuleAttributesResponse
|
||||
*/
|
||||
export type GetDealModuleAttributesResponse = {
|
||||
/**
|
||||
* Attributes
|
||||
*/
|
||||
attributes: Array<DealModuleAttributeSchema>;
|
||||
};
|
||||
|
||||
/**
|
||||
* GetDealProductsResponse
|
||||
*/
|
||||
@ -2501,6 +2562,42 @@ export type UpdateDealGroupSchema = {
|
||||
statusId?: number | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* UpdateDealModuleAttributeSchema
|
||||
*/
|
||||
export type UpdateDealModuleAttributeSchema = {
|
||||
/**
|
||||
* Attributeid
|
||||
*/
|
||||
attributeId: number;
|
||||
/**
|
||||
* Value
|
||||
*/
|
||||
value: {
|
||||
[key: string]: unknown;
|
||||
} | null;
|
||||
};
|
||||
|
||||
/**
|
||||
* UpdateDealModuleAttributesRequest
|
||||
*/
|
||||
export type UpdateDealModuleAttributesRequest = {
|
||||
/**
|
||||
* Attributes
|
||||
*/
|
||||
attributes: Array<UpdateDealModuleAttributeSchema>;
|
||||
};
|
||||
|
||||
/**
|
||||
* UpdateDealModuleAttributesResponse
|
||||
*/
|
||||
export type UpdateDealModuleAttributesResponse = {
|
||||
/**
|
||||
* Message
|
||||
*/
|
||||
message: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* UpdateDealProductRequest
|
||||
*/
|
||||
@ -3177,6 +3274,78 @@ export type GetAttributeTypesResponses = {
|
||||
export type GetAttributeTypesResponse =
|
||||
GetAttributeTypesResponses[keyof GetAttributeTypesResponses];
|
||||
|
||||
export type GetDealModuleAttributesData = {
|
||||
body?: never;
|
||||
path: {
|
||||
/**
|
||||
* Dealid
|
||||
*/
|
||||
dealId: number;
|
||||
/**
|
||||
* Moduleid
|
||||
*/
|
||||
moduleId: number;
|
||||
};
|
||||
query?: never;
|
||||
url: "/crm/v1/attribute/deal/{dealId}/module/{moduleId}";
|
||||
};
|
||||
|
||||
export type GetDealModuleAttributesErrors = {
|
||||
/**
|
||||
* Validation Error
|
||||
*/
|
||||
422: HttpValidationError;
|
||||
};
|
||||
|
||||
export type GetDealModuleAttributesError =
|
||||
GetDealModuleAttributesErrors[keyof GetDealModuleAttributesErrors];
|
||||
|
||||
export type GetDealModuleAttributesResponses = {
|
||||
/**
|
||||
* Successful Response
|
||||
*/
|
||||
200: GetDealModuleAttributesResponse;
|
||||
};
|
||||
|
||||
export type GetDealModuleAttributesResponse2 =
|
||||
GetDealModuleAttributesResponses[keyof GetDealModuleAttributesResponses];
|
||||
|
||||
export type UpdateDealModuleAttributesData = {
|
||||
body: UpdateDealModuleAttributesRequest;
|
||||
path: {
|
||||
/**
|
||||
* Dealid
|
||||
*/
|
||||
dealId: number;
|
||||
/**
|
||||
* Moduleid
|
||||
*/
|
||||
moduleId: number;
|
||||
};
|
||||
query?: never;
|
||||
url: "/crm/v1/attribute/deal/{dealId}/module/{moduleId}";
|
||||
};
|
||||
|
||||
export type UpdateDealModuleAttributesErrors = {
|
||||
/**
|
||||
* Validation Error
|
||||
*/
|
||||
422: HttpValidationError;
|
||||
};
|
||||
|
||||
export type UpdateDealModuleAttributesError =
|
||||
UpdateDealModuleAttributesErrors[keyof UpdateDealModuleAttributesErrors];
|
||||
|
||||
export type UpdateDealModuleAttributesResponses = {
|
||||
/**
|
||||
* Successful Response
|
||||
*/
|
||||
200: UpdateDealModuleAttributesResponse;
|
||||
};
|
||||
|
||||
export type UpdateDealModuleAttributesResponse2 =
|
||||
UpdateDealModuleAttributesResponses[keyof UpdateDealModuleAttributesResponses];
|
||||
|
||||
export type GetBoardsData = {
|
||||
body?: never;
|
||||
path: {
|
||||
|
||||
@ -827,6 +827,23 @@ export const zDealAddKitResponse = z.object({
|
||||
message: z.string(),
|
||||
});
|
||||
|
||||
/**
|
||||
* DealModuleAttributeSchema
|
||||
*/
|
||||
export const zDealModuleAttributeSchema = z.object({
|
||||
attributeId: z.int(),
|
||||
label: z.string(),
|
||||
originalLabel: z.string(),
|
||||
value: z.union([z.object({}), z.null()]),
|
||||
type: zAttributeTypeSchema,
|
||||
defaultValue: z.object({}),
|
||||
description: z.string(),
|
||||
isApplicableToGroup: z.boolean(),
|
||||
isShownOnDashboard: z.boolean(),
|
||||
isHighlightIfExpired: z.boolean(),
|
||||
isNullable: z.boolean(),
|
||||
});
|
||||
|
||||
/**
|
||||
* DealProductAddKitRequest
|
||||
*/
|
||||
@ -1093,6 +1110,13 @@ export const zGetClientsResponse = z.object({
|
||||
items: z.array(zClientSchema),
|
||||
});
|
||||
|
||||
/**
|
||||
* GetDealModuleAttributesResponse
|
||||
*/
|
||||
export const zGetDealModuleAttributesResponse = z.object({
|
||||
attributes: z.array(zDealModuleAttributeSchema),
|
||||
});
|
||||
|
||||
/**
|
||||
* GetDealProductsResponse
|
||||
*/
|
||||
@ -1441,6 +1465,28 @@ export const zUpdateDealGroupResponse = z.object({
|
||||
message: z.string(),
|
||||
});
|
||||
|
||||
/**
|
||||
* UpdateDealModuleAttributeSchema
|
||||
*/
|
||||
export const zUpdateDealModuleAttributeSchema = z.object({
|
||||
attributeId: z.int(),
|
||||
value: z.union([z.object({}), z.null()]),
|
||||
});
|
||||
|
||||
/**
|
||||
* UpdateDealModuleAttributesRequest
|
||||
*/
|
||||
export const zUpdateDealModuleAttributesRequest = z.object({
|
||||
attributes: z.array(zUpdateDealModuleAttributeSchema),
|
||||
});
|
||||
|
||||
/**
|
||||
* UpdateDealModuleAttributesResponse
|
||||
*/
|
||||
export const zUpdateDealModuleAttributesResponse = z.object({
|
||||
message: z.string(),
|
||||
});
|
||||
|
||||
/**
|
||||
* UpdateDealProductSchema
|
||||
*/
|
||||
@ -1837,6 +1883,36 @@ export const zGetAttributeTypesData = z.object({
|
||||
*/
|
||||
export const zGetAttributeTypesResponse = zGetAllAttributeTypesResponse;
|
||||
|
||||
export const zGetDealModuleAttributesData = z.object({
|
||||
body: z.optional(z.never()),
|
||||
path: z.object({
|
||||
dealId: z.int(),
|
||||
moduleId: z.int(),
|
||||
}),
|
||||
query: z.optional(z.never()),
|
||||
});
|
||||
|
||||
/**
|
||||
* Successful Response
|
||||
*/
|
||||
export const zGetDealModuleAttributesResponse2 =
|
||||
zGetDealModuleAttributesResponse;
|
||||
|
||||
export const zUpdateDealModuleAttributesData = z.object({
|
||||
body: zUpdateDealModuleAttributesRequest,
|
||||
path: z.object({
|
||||
dealId: z.int(),
|
||||
moduleId: z.int(),
|
||||
}),
|
||||
query: z.optional(z.never()),
|
||||
});
|
||||
|
||||
/**
|
||||
* Successful Response
|
||||
*/
|
||||
export const zUpdateDealModuleAttributesResponse2 =
|
||||
zUpdateDealModuleAttributesResponse;
|
||||
|
||||
export const zGetBoardsData = z.object({
|
||||
body: z.optional(z.never()),
|
||||
path: z.object({
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
import { ProjectSchema } from "../../client";
|
||||
import { ModuleNames } from "../modules.tsx";
|
||||
import { ProjectSchema } from "@/lib/client";
|
||||
import { ModuleNames } from "../modules";
|
||||
|
||||
const isModuleInProject = (module: ModuleNames, project?: ProjectSchema | null) => {
|
||||
const isModuleInProject = (
|
||||
module: ModuleNames,
|
||||
project?: ProjectSchema | null
|
||||
) => {
|
||||
return project?.modules.findIndex(m => m.key === module.toString()) !== -1;
|
||||
};
|
||||
|
||||
|
||||
@ -1,5 +1,9 @@
|
||||
import { formatInTimeZone } from "date-fns-tz";
|
||||
|
||||
export const naiveDateTimeStringToUtc = (datetime: string) => {
|
||||
return `${datetime.replace(" ", "T")}Z`;
|
||||
};
|
||||
|
||||
export const utcDateToLocal = (datetime: string | Date) => {
|
||||
const userTZ = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
const localTime = formatInTimeZone(datetime, userTZ, "yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
10
yarn.lock
10
yarn.lock
@ -6185,7 +6185,7 @@ __metadata:
|
||||
clsx: "npm:^2.1.1"
|
||||
date-fns: "npm:^4.1.0"
|
||||
date-fns-tz: "npm:^3.2.0"
|
||||
dayjs: "npm:^1.11.15"
|
||||
dayjs: "npm:^1.11.18"
|
||||
eslint: "npm:^9.29.0"
|
||||
eslint-config-mantine: "npm:^4.0.3"
|
||||
eslint-plugin-eslint-comments: "npm:^3.2.0"
|
||||
@ -6425,10 +6425,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dayjs@npm:^1.11.15":
|
||||
version: 1.11.15
|
||||
resolution: "dayjs@npm:1.11.15"
|
||||
checksum: 10c0/bb66cd5419fff017f3950b95fc27643cf4e0ce22a087cef1f67398f18126ed07bf36d6911f33b19029a1621c64090b8ecaef660477de7678287fe8c0f4e68d29
|
||||
"dayjs@npm:^1.11.18":
|
||||
version: 1.11.18
|
||||
resolution: "dayjs@npm:1.11.18"
|
||||
checksum: 10c0/83b67f5d977e2634edf4f5abdd91d9041a696943143638063016915d2cd8c7e57e0751e40379a07ebca8be7a48dd380bef8752d22a63670f2d15970e34f96d7a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
||||
Reference in New Issue
Block a user