Skip to content

Instantly share code, notes, and snippets.

@mushfiqweb
Created March 28, 2024 04:41
Show Gist options
  • Save mushfiqweb/97ae0d2b990b9abc4692b3f5c4aeda62 to your computer and use it in GitHub Desktop.
Save mushfiqweb/97ae0d2b990b9abc4692b3f5c4aeda62 to your computer and use it in GitHub Desktop.
import { BaseMsisdn } from '@/@types/product';
import { SegmentItemOption } from '@/components/shared';
import { Card, DatePicker, Segment, Select } from '@/components/ui';
import { FormItem } from '@/components/ui/Form';
import type { InputProps } from '@/components/ui/Input';
import Input from '@/components/ui/Input';
import CaseConversion from '@/utils/caseConversion';
import {
useGetMsisdnDataQuery,
useGetProductMetaDataQuery,
} from '@/views/connect/Product/store/productsApi';
import classNames from 'classnames';
import { Field, FieldProps, FormikErrors, FormikTouched } from 'formik';
import { HiCheckCircle } from 'react-icons/hi';
import { MdOutlineWarning } from 'react-icons/md';
type Option = {
label: string;
value: string;
};
type FormFieldsName = {
sim_type: number;
product_code: string;
name: string;
commercial_name_en: string;
commercial_name_bn: string;
display_title_en?: string;
display_title_bn?: string;
short_description: string;
display_sd_vat_tax?: string;
vat?: number;
mrp_price?: number;
price?: number;
points?: number;
validity: number;
validity_unit: string;
renew_product_code?: string;
recharge_product_code?: string;
tags?: Option[];
special_type?: string;
show_from?: string | Date;
hide_from?: string | Date;
base_msisdn_group_id?: string | number;
content_filter_tags?: string;
// is_visible: boolean | number;
};
type BasicInformationFields = {
type: 'edit' | 'new';
touched: FormikTouched<FormFieldsName>;
errors: FormikErrors<FormFieldsName>;
values: FormFieldsName;
};
const connectionTypeSelections = [
{ value: '1', label: 'Prepaid' },
{ value: '2', label: 'Postpaid' },
];
const NumberInput = (props: InputProps) => {
return (
<Input {...props} value={props.field.value} type="number" suffix="" />
);
};
const mapBaseMsisdn = (data: BaseMsisdn[]): Option[] => {
return data.map((item) => ({
value: item?.id?.toString() || '',
label: item.title,
}));
};
const BasicInformationFields = (props: BasicInformationFields) => {
const {
values = {
tags: [],
sim_type: 1,
validity_unit: '',
special_type: '',
base_msisdn_group_id: '',
},
touched,
errors,
type,
} = props;
const { data: productMetaData } = useGetProductMetaDataQuery();
const { data: msisdnData } = useGetMsisdnDataQuery();
return (
<Card className="col-span-1 shadow-sm">
<h5>Basic Information</h5>
<p className="mb-6">Section to config basic product information</p>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{/*--- connection type ---*/}
{type === 'new' && (
<FormItem
asterisk
className="mb-2 col-span-full"
label="Connection Type"
invalid={Boolean(errors.sim_type && touched.sim_type)}
errorMessage={errors.sim_type as string}
>
<Field name="sim_type">
{({ field, form }: FieldProps) => (
<Segment
className="w-full"
defaultValue={values.sim_type?.toString()}
selectionType="single"
onChange={(val) =>
form.setFieldValue(
field.name,
parseInt(val.toString())
)
}
>
<div className="grid grid-cols-2 gap-4 w-full">
{connectionTypeSelections.map(
(connectionType) => (
<Segment.Item
key={connectionType.value}
value={connectionType.value}
// disabled={type === 'edit'}
>
{({
active,
onSegmentItemClick,
disabled,
}) => {
return (
<div className="text-center">
<SegmentItemOption
hoverable
active={
active
}
disabled={
disabled
}
defaultGutter={
false
}
className="relative min-h-[40px] w-full"
customCheck={
<HiCheckCircle className="text-indigo-600 absolute top-2 right-2 text-lg" />
}
onSegmentItemClick={
onSegmentItemClick
}
>
<div className="flex flex-col items-start mx-4">
<h6>
{CaseConversion.toTitleCase(
connectionType.label
)}
</h6>
</div>
</SegmentItemOption>
</div>
);
}}
</Segment.Item>
)
)}
</div>
</Segment>
)}
</Field>
</FormItem>
)}
{/*--- product code & product name */}
<div className="grid grid-cols-1 md:grid-cols-2 col-span-full gap-4">
{type === 'new' && (
<FormItem
asterisk
className="mb-2"
label="Product Code"
invalid={
(errors.product_code &&
touched.product_code) as boolean
}
errorMessage={errors.product_code}
>
<Field
type="text"
// disabled={type === 'edit'}
autoComplete="off"
name="product_code"
placeholder="Product Code"
component={Input}
size="sm"
/>
</FormItem>
)}
<FormItem
asterisk
className={classNames(
'mb-2',
type === 'edit' && 'col-span-full'
)}
label="Product Name"
size="xs"
invalid={(errors.name && touched.name) as boolean}
errorMessage={errors.name}
>
<Field
type="text"
autoComplete="off"
name="name"
placeholder="Product Name"
component={Input}
size="sm"
/>
</FormItem>
</div>
{/*--- commercial name en & bn ---*/}
<div className="grid grid-cols-1 md:grid-cols-2 col-span-full gap-4">
<FormItem
asterisk
className="mb-2"
size="xs"
label="Commercial Name En"
invalid={
(errors.commercial_name_en &&
touched.commercial_name_en) as boolean
}
errorMessage={errors.commercial_name_en}
>
<Field
type="text"
autoComplete="off"
name="commercial_name_en"
placeholder="Commercial Name En"
component={Input}
size="sm"
/>
</FormItem>
<FormItem
asterisk
className="mb-2"
size="xs"
label="Commercial Name Bn"
invalid={
(errors.commercial_name_bn &&
touched.commercial_name_bn) as boolean
}
errorMessage={errors.commercial_name_bn}
>
<Field
type="text"
autoComplete="off"
name="commercial_name_bn"
placeholder="Commercial Name Bn"
component={Input}
size="sm"
/>
</FormItem>
</div>
{/*--- display title en & bn ---*/}
<div className="grid grid-cols-1 md:grid-cols-2 col-span-full gap-4">
<FormItem
className="mb-2"
label="Display Title En"
size="xs"
invalid={
(errors.display_title_en &&
touched.display_title_en) as boolean
}
errorMessage={errors.display_title_en}
>
<Field
type="text"
autoComplete="off"
name="display_title_en"
placeholder="Display Title En"
component={Input}
size="sm"
/>
</FormItem>
<FormItem
className="mb-2"
label="Display Title Bn"
size="xs"
invalid={
(errors.display_title_bn &&
touched.display_title_bn) as boolean
}
errorMessage={errors.display_title_bn}
>
<Field
type="text"
autoComplete="off"
name="display_title_bn"
placeholder="Display Title Bn"
component={Input}
size="sm"
/>
</FormItem>
</div>
{/*--- short description ---*/}
<FormItem
className="col-span-full mb-2"
label="Short Description"
labelClass="!justify-start"
invalid={
(errors.short_description &&
touched.short_description) as boolean
}
errorMessage={errors.short_description}
>
<Field
textArea
name="short_description"
placeholder="Short Description"
component={Input}
/>
</FormItem>
{/*--- display sd vat tax & vat ---*/}
<div className="grid grid-cols-1 md:grid-cols-2 col-span-full gap-4">
<FormItem
className="mb-2"
label="Display Sd Vat Tax"
size="xs"
invalid={
(errors.display_sd_vat_tax &&
touched.display_sd_vat_tax) as boolean
}
errorMessage={errors.display_sd_vat_tax}
>
<Field
type="text"
autoComplete="off"
name="display_sd_vat_tax"
placeholder="Display Sd Vat Tax"
component={Input}
size="sm"
/>
</FormItem>
<FormItem
className="mb-0"
size="sm"
label="VAT"
invalid={(errors.vat && touched.vat) as boolean}
errorMessage={errors.vat}
>
<Field size="sm" name="vat">
{({ field }: FieldProps) => {
return (
<NumberInput
placeholder="VAT"
field={field}
size="sm"
/>
);
}}
</Field>
</FormItem>
</div>
{/*--- mrp price & price ---*/}
<div className="grid grid-cols-1 md:grid-cols-2 col-span-full gap-4">
<FormItem
asterisk
className="mb-0"
label="MRP Price"
invalid={
(errors.mrp_price && touched.mrp_price) as boolean
}
errorMessage={errors.mrp_price}
>
<Field name="mrp_price">
{({ field }: FieldProps) => {
return (
<NumberInput
placeholder="MRP Price"
field={field}
size="sm"
/>
);
}}
</Field>
</FormItem>
<FormItem
className="mb-0"
size="sm"
label="Price"
invalid={(errors.price && touched.price) as boolean}
errorMessage={errors.price}
>
<Field size="sm" name="price">
{({ field, form }: FieldProps) => {
return (
<NumberInput
placeholder="Price"
field={field}
size="sm"
/>
);
}}
</Field>
</FormItem>
</div>
{/*--- points, validity & validity unit ---*/}
<div className="grid grid-cols-1 md:grid-cols-3 col-span-full gap-4">
<FormItem
size="sm"
className="mb-0"
label="Points"
invalid={(errors.points && touched.points) as boolean}
errorMessage={errors.points}
>
<Field size="sm" name="points">
{({ field, form }: FieldProps) => {
return (
<NumberInput
placeholder="Points"
field={field}
size="sm"
/>
);
}}
</Field>
</FormItem>
<FormItem
asterisk
size="sm"
className="mb-0"
label="Validity"
invalid={
(errors.validity && touched.validity) as boolean
}
errorMessage={errors.validity}
>
<Field size="sm" name="validity">
{({ field, form }: FieldProps) => {
return (
<NumberInput
placeholder="Validity"
field={field}
size="sm"
/>
);
}}
</Field>
</FormItem>
<FormItem
asterisk
label="Validity Unit"
invalid={
(errors.validity_unit &&
touched.validity_unit) as boolean
}
errorMessage={errors.validity_unit}
size="sm"
className="mb-0"
>
<Field size="sm" name="validity_unit">
{({ field, form }: FieldProps) => (
<Select
size="sm"
field={field}
form={form}
options={
productMetaData?.data
.validityUnitSelections
}
value={productMetaData?.data.validityUnitSelections.filter(
(validity_unit) =>
validity_unit?.value?.toLowerCase() ===
values?.validity_unit?.toLowerCase()
)}
onChange={(option) =>
form.setFieldValue(
field.name,
option?.value
)
}
/>
)}
</Field>
</FormItem>
</div>
{/*--- auto renewable & recharge product code ---*/}
<div className="grid grid-cols-1 md:grid-cols-2 col-span-full gap-4">
<FormItem
className="mb-2"
label="Auto Renewable Code"
size="sm"
invalid={
(errors.renew_product_code &&
touched.renew_product_code) as boolean
}
errorMessage={errors.renew_product_code}
>
<Field
type="text"
autoComplete="off"
name="renew_product_code"
placeholder="Auto Renewable Code"
component={Input}
size="sm"
/>
</FormItem>
<FormItem
className="mb-2"
label="Recharge Product Code"
size="sm"
invalid={
(errors.recharge_product_code &&
touched.recharge_product_code) as boolean
}
errorMessage={errors.recharge_product_code}
>
<Field
type="text"
autoComplete="off"
name="recharge_product_code"
placeholder="Recharge Product Code"
component={Input}
size="sm"
/>
</FormItem>
</div>
{/*--- tags ---*/}
<FormItem
className="col-span-full mb-2"
label="Tags"
size="sm"
invalid={
(errors.tags && touched.tags) as unknown as boolean
}
errorMessage={errors.tags as string}
>
<Field name="tags" size="sm">
{({ field, form }: FieldProps) => (
<Select
isClearable
field={field}
form={form}
options={productMetaData?.data.tagSelections}
value={values.tags}
size="sm"
onChange={(option) =>
form.setFieldValue(field.name, option)
}
/>
)}
</Field>
</FormItem>
{/*--- content_filter_tags ---*/}
<div className="grid grid-cols-1 col-span-full gap-4">
<FormItem
className="mb-2"
label="Content Filter Tags"
invalid={
(errors.content_filter_tags &&
touched.content_filter_tags) as unknown as boolean
}
errorMessage={errors.content_filter_tags as string}
info="Content Filter Tags should be Comma-separated value. Example: data,toffee"
>
<Field
type="text"
autoComplete="off"
name="content_filter_tags"
placeholder="Content Filter Tags"
component={Input}
size="sm"
/>
</FormItem>
</div>
{/*--- special type ---*/}
<FormItem
label="Special Type"
invalid={
(errors.special_type && touched.special_type) as boolean
}
errorMessage={errors.special_type}
size="sm"
className="col-span-2 mb-0"
>
<Field size="sm" name="special_type">
{({ field, form }: FieldProps) => (
<Select
isClearable
size="sm"
field={field}
form={form}
options={
productMetaData?.data.specialTypeSelections
}
value={productMetaData?.data.specialTypeSelections.filter(
(special_type) =>
special_type.value.toString() ===
values?.special_type?.toString()
)}
onChange={(option) =>
form.setFieldValue(
field.name,
option?.value?.toString()
)
}
/>
)}
</Field>
</FormItem>
{/*--- schedule availability ---*/}
<>
<p className="font-[600] text-sm text-inherit">
Schedule Availability
</p>
<div className="grid grid-cols-1 col-span-full gap-4">
<FormItem
layout="horizontal"
className="mb-0"
size="sm"
label="Show From"
invalid={
(errors.show_from &&
touched.show_from) as boolean
}
errorMessage={errors.show_from as string}
>
<Field size="sm" name="show_from">
{({ field, form }: FieldProps) => (
<DatePicker.DateTimepicker
disableDate={(date) => {
const today = new Date();
today.setHours(0, 0, 0, 0);
return date < today;
}}
size="sm"
placeholder="Show From Time"
field={field}
form={form}
value={field.value}
onChange={(date) => {
form.setFieldValue(
field.name,
date
);
}}
/>
)}
</Field>
</FormItem>
<FormItem
layout="horizontal"
className="mb-0"
size="sm"
label="Hide From"
invalid={
(errors.hide_from &&
touched.hide_from) as boolean
}
errorMessage={errors.hide_from as string}
>
<Field size="sm" name="hide_from">
{({ field, form }: FieldProps) => (
<DatePicker.DateTimepicker
disableDate={(date) => {
const today = new Date();
today.setHours(0, 0, 0, 0);
return date < today;
}}
size="sm"
placeholder="Hide From Time"
field={field}
form={form}
value={field.value}
onChange={(date) => {
form.setFieldValue(
field.name,
date
);
}}
/>
)}
</Field>
</FormItem>
</div>
</>
{/*----- base msisdn -----*/}
<div className="grid grid-cols-1 gap-4 col-span-full">
<FormItem
className="mb-0"
label="Base MSISDN"
invalid={
(errors.base_msisdn_group_id &&
touched.base_msisdn_group_id) as boolean
}
errorMessage={errors.base_msisdn_group_id}
>
<Field size="sm" name="base_msisdn_group_id">
{({ field, form }: FieldProps) => (
<Select
isClearable
placeholder="No Base Msisdn Group Selected"
field={field}
form={form}
size="sm"
options={mapBaseMsisdn(
msisdnData?.data || []
)}
value={mapBaseMsisdn(
msisdnData?.data || []
).filter(
(group_id) =>
group_id.value?.toString() ===
values.base_msisdn_group_id?.toString()
)}
onChange={(option) =>
form.setFieldValue(
field.name,
option?.value
)
}
/>
)}
</Field>
<div className="text-orange-500 flex gap-2 mt-1">
<MdOutlineWarning size={20} />
<span>
<strong>Warning:</strong> If you don&apos;t
select a base group, this product is available
for connection type-wise users.
</span>
</div>
</FormItem>
</div>
</div>
</Card>
);
};
export default BasicInformationFields;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment