upload foto, dan bugs import

This commit is contained in:
pajri
2022-12-21 17:22:45 +07:00
parent 88ad144921
commit b1c908a6f6
12 changed files with 576 additions and 169 deletions

View File

@@ -18,6 +18,8 @@ use Illuminate\Http\Request;
use Illuminate\Routing\Controller; use Illuminate\Routing\Controller;
use Maatwebsite\Excel\Facades\Excel; use Maatwebsite\Excel\Facades\Excel;
use Box\Spout\Reader\Common\Creator\ReaderEntityFactory; use Box\Spout\Reader\Common\Creator\ReaderEntityFactory;
use App\Models\File;
use Illuminate\Support\Facades\Storage; use Illuminate\Support\Facades\Storage;
use Modules\Internal\Services\CorporateService; use Modules\Internal\Services\CorporateService;
@@ -220,6 +222,18 @@ class CorporateController extends Controller
$managerOne = User::where('email', 'manager+one@gmail.com')->first(); $managerOne = User::where('email', 'manager+one@gmail.com')->first();
$managerOne->managedCorporates()->attach($newCorporate); $managerOne->managedCorporates()->attach($newCorporate);
if ($request->hasFile('logo')) {
$pathFileAvatar = File::storeFile('avatar', $newCorporate->id, $request->file('logo'));
$newCorporate->files()->updateOrCreate([
'type' => 'avatar',
'name' => File::getFileName('avatar', $newCorporate->id, $request->file('logo')),
'extension' => $request->file('logo')->getClientOriginalExtension(),
'path' => $pathFileAvatar,
'created_by' => auth()->user()->id,
'updated_by' => auth()->user()->id,
]);
}
DB::commit(); DB::commit();
} catch (\Exception $e) { } catch (\Exception $e) {
@@ -282,9 +296,13 @@ class CorporateController extends Controller
try { try {
DB::beginTransaction(); DB::beginTransaction();
//karena pake formdata
$linkingRules = $request->linking_rules;
$linkingRules = explode(',', $linkingRules);
$corporate = Corporate::findOrFail($id); $corporate = Corporate::findOrFail($id);
$corporate->fill($request->toArray()); $corporate->fill($request->all());
$corporate->linking_rules = $linkingRules;
$corporate->save(); $corporate->save();
$corporate->policies()->updateOrCreate( $corporate->policies()->updateOrCreate(
@@ -304,6 +322,19 @@ class CorporateController extends Controller
] ]
); );
if ($request->hasFile('logo')) {
$pathFileAvatar = File::storeFile('avatar', $corporate->id, $request->file('logo'));
$corporate->files()->updateOrCreate([
'type' => 'avatar',
'name' => File::getFileName('avatar', $corporate->id, $request->file('logo')),
'extension' => $request->file('logo')->getClientOriginalExtension(),
'path' => $pathFileAvatar,
'created_by' => auth()->user()->id,
'updated_by' => auth()->user()->id,
]);
}
DB::commit(); DB::commit();
} catch (\Exception $e) { } catch (\Exception $e) {
DB::rollBack(); DB::rollBack();

View File

@@ -84,12 +84,16 @@ class CorporateService
public function handleBenefitRow(Corporate $corporate, $row) public function handleBenefitRow(Corporate $corporate, $row)
{ {
try { try {
$benefit_data = $row; $benefit_data = $row;
$benefit_data["corporate_id"] = $corporate->id; $benefit_data["corporate_id"] = $corporate->id;
$this->validateBenefitRow($benefit_data); $this->validateBenefitRow($benefit_data);
$plan = $corporate->plans->where('corporate_plan_id', $benefit_data['plan_code'])->first();
$plan = Plan::where('corporate_plan_id', $benefit_data['plan_code'])->first();
// $corporate->plans->where('corporate_plan_id', $benefit_data['plan_code'])->first();
$benefit_data['plan_code'] = $plan->id; $benefit_data['plan_code'] = $plan->id;
$benefit = Benefit::updateOrCreate([ $benefit = Benefit::updateOrCreate([
@@ -104,11 +108,11 @@ class CorporateService
$corporateBenefit = $corporate->corporateBenefits()->updateOrCreate([ $corporateBenefit = $corporate->corporateBenefits()->updateOrCreate([
'benefit_id' => $benefit->id, 'benefit_id' => $benefit->id,
'plan_id' => $plan->id 'plan_id' => $plan->id
], $benefit_data ); ], $benefit_data);
return $corporateBenefit; return $corporateBenefit;
} catch (\Exception $e) { } catch (\Exception $e) {
dd($e->getMessage()); // dd($e->getMessage());
throw $e; throw $e;
} }
} }

View File

@@ -362,8 +362,8 @@ class MemberEnrollmentService
"nik" => $row['nik'] ?? null, "nik" => $row['nik'] ?? null,
"birth_date" => Carbon::parse(strtotime($row['date_of_birth'])), "birth_date" => Carbon::parse(strtotime($row['date_of_birth'])),
"gender" => Helper::genderNormalization($row['sex']), "gender" => Helper::genderNormalization($row['sex']),
"language" => $row['language'] ?? null, // "language" => $row['language'] ?? null,
"race" => $row['race'] ?? null, // "race" => $row['race'] ?? null,
"marital_status" => $row['marital_status'] ?? null, "marital_status" => $row['marital_status'] ?? null,
"record_type" => $row['record_type'] ?? null, "record_type" => $row['record_type'] ?? null,
"principal_id" => $row['principal_id'] ?? null, "principal_id" => $row['principal_id'] ?? null,
@@ -429,15 +429,6 @@ class MemberEnrollmentService
]), 0, null, $row); ]), 0, null, $row);
} else { } else {
$member = new Member(); $member = new Member();
$person = Person::create([
'name' => $row['name'],
'birth_date' => Carbon::parse(strtotime($row['date_of_birth'])),
'gender' => Helper::genderPerson($row['sex']),
'language' => $row['language'] ?? null,
'race' => $row['race'] ?? null,
]);
$member->person_id = $person->id;
$member->save();
} }
$memberPolicy = $member->policies() $memberPolicy = $member->policies()
@@ -463,10 +454,22 @@ class MemberEnrollmentService
$this->validateRow($row); $this->validateRow($row);
try { try {
DB::beginTransaction(); DB::beginTransaction();
$member->fill($member_data); $member->fill($member_data);
if ($member->save()) { if ($member->save()) {
$person = Person::create([
'name' => $row['name'],
'birth_date' => Carbon::parse(strtotime($row['date_of_birth'])),
'gender' => Helper::genderPerson($row['sex']),
'language' => $row['language'] ?? null,
'race' => $row['race'] ?? null,
]);
$member->person_id = $person->id;
$member->save();
$memberPolicy = new MemberPolicy(); $memberPolicy = new MemberPolicy();
$memberPolicy->fill([ $memberPolicy->fill([
'member_id' => $member->member_id, 'member_id' => $member->member_id,

View File

@@ -11,7 +11,7 @@ class ImportRowException extends Exception
public function __construct($message, $code = 0, Throwable $previous = null, $data) public function __construct($message, $code = 0, Throwable $previous = null, $data)
{ {
parent::__construct($message, $code, $previous); parent::__construct($message, (int)$code, $previous);
$this->data = $data; $this->data = $data;
} }

View File

@@ -26,6 +26,10 @@ class Corporate extends Model
'linking_rules' => 'array', 'linking_rules' => 'array',
]; ];
protected $appends = [
'avatar_url',
];
public function imports() public function imports()
{ {
return $this->morphMany(ImportLog::class, 'importable'); return $this->morphMany(ImportLog::class, 'importable');
@@ -36,6 +40,16 @@ class Corporate extends Model
return $this->morphMany(File::class, 'fileable'); return $this->morphMany(File::class, 'fileable');
} }
public function avatar()
{
return $this->morphOne(File::class, 'fileable')->where('type', 'avatar')->latest();
}
public function getAvatarUrlAttribute()
{
return $this->avatar ? $this->avatar->url : null;
}
public function plans() public function plans()
{ {
return $this->hasMany(Plan::class, 'corporate_id', 'id'); return $this->hasMany(Plan::class, 'corporate_id', 'id');

View File

@@ -22,6 +22,8 @@ class Person extends Model
'gender', 'gender',
'birth_date', 'birth_date',
'birth_place', 'birth_place',
'language',
'race',
'citizenship', 'citizenship',
'current_employment', 'current_employment',
'last_education', 'last_education',

View File

@@ -0,0 +1,93 @@
import React, { Dispatch, FunctionComponent, useCallback, useState } from 'react';
import { useDropzone } from 'react-dropzone';
import { Box, Stack, Typography } from '@mui/material';
import BlockContent from './upload/BlockContent';
import { styled } from '@mui/material/styles';
import { UploadIllustration } from '../assets';
const DropZoneStyle = styled('div')(({ theme }) => ({
outline: 'none',
overflow: 'hidden',
position: 'relative',
padding: theme.spacing(5, 1),
borderRadius: theme.shape.borderRadius,
transition: theme.transitions.create('padding'),
// backgroundColor: theme.palette.background.neutral,
backgroundColor: '#ffffff',
border: `2px dashed ${theme.palette.grey[500_32]}`,
'&:hover': { cursor: 'pointer', backgroundColor: '#f7f7f7' },
}));
const MyDropzone: FunctionComponent<{
setFile: Dispatch<any>;
currentImage: string;
}> = ({
setFile,
currentImage,
// onChanges,
}) => {
const onDrop = useCallback((acceptedFiles) => {
// Do something with the files
console.log(acceptedFiles);
setFile(acceptedFiles[0]);
setImage(acceptedFiles[0]);
// onChanges(acceptedFiles[0]);
}, []);
const { getRootProps, getInputProps, isDragActive, isDragReject } = useDropzone({
onDrop,
multiple: false,
});
const [image, setImage] = useState<File | null>(null);
return (
<DropZoneStyle
{...getRootProps()}
sx={{
...(isDragActive && { opacity: 2.72 }),
}}
>
<input {...getInputProps()} />
<Stack
spacing={2}
alignItems="center"
justifyContent="center"
direction={{ xs: 'column', md: 'row' }}
sx={{ width: 1, textAlign: { xs: 'center', md: 'left' } }}
>
{image ? (
<img src={URL.createObjectURL(image)} alt="preview" width={220} />
) : currentImage ? (
<img src={currentImage} alt="preview" width={220} />
) : (
<UploadIllustration sx={{ width: 220 }} />
)}
<Box sx={{ p: 3 }}>
<Typography gutterBottom variant="h5">
Pilih Foto
</Typography>
<Typography variant="body2" sx={{ color: 'text.secondary' }}>
Letakkan foto disini atau klik jelajahi &nbsp;
<Typography
variant="body2"
component="span"
sx={{ color: 'primary.main', textDecoration: 'underline' }}
>
jelajahi
</Typography>
&nbsp;foto di perangkat Anda
</Typography>
</Box>
</Stack>
{/* <BlockContent file={image} /> */}
{isDragReject && <p>Unsupported file type...</p>}
</DropZoneStyle>
);
};
export default MyDropzone;

View File

@@ -0,0 +1,128 @@
import React, { Dispatch, FunctionComponent, useCallback, useState } from 'react';
import { useDropzone } from 'react-dropzone';
import { Box, Stack, Typography } from '@mui/material';
import BlockContent from './upload/BlockContent';
import { styled } from '@mui/material/styles';
import { UploadIllustration } from '../assets';
import Iconify from './Iconify';
const RootStyle = styled('div')(({ theme }) => ({
width: 144,
height: 144,
margin: 'auto',
borderRadius: '50%',
padding: theme.spacing(1),
border: `2px dashed ${theme.palette.grey[500_32]}`,
}));
const DropZoneStyle = styled('div')({
zIndex: 0,
width: '100%',
height: '100%',
outline: 'none',
display: 'flex',
overflow: 'hidden',
borderRadius: '50%',
position: 'relative',
alignItems: 'center',
justifyContent: 'center',
'& > *': { width: '100%', height: '100%' },
'&:hover': {
cursor: 'pointer',
'& .placeholder': {
zIndex: 9,
},
},
});
const PlaceholderStyle = styled('div')(({ theme }) => ({
display: 'flex',
position: 'absolute',
alignItems: 'center',
flexDirection: 'column',
justifyContent: 'center',
color: theme.palette.text.secondary,
// backgroundColor: theme.palette.background.neutral,
transition: theme.transitions.create('opacity', {
easing: theme.transitions.easing.easeInOut,
duration: theme.transitions.duration.shorter,
}),
'&:hover': { opacity: 0.72 },
}));
const UploadImage: FunctionComponent<{
setFile: Dispatch<any>;
currentImage: string;
}> = ({ setFile, currentImage, setSave, error, file, helperText, sx, ...other }) => {
const onDrop = useCallback(
(acceptedFiles) => {
// Do something with the files
console.log(acceptedFiles);
setFile(acceptedFiles[0]);
setImage(acceptedFiles[0]);
},
[setFile, setSave]
);
const { getRootProps, getInputProps, isDragActive, isDragReject } = useDropzone({
onDrop,
multiple: false,
});
const [image, setImage] = useState<File | null>(null);
return (
<RootStyle
sx={{
...((isDragReject || error) && {
borderColor: 'error.light',
}),
...sx,
}}
>
<DropZoneStyle
{...getRootProps()}
sx={{
...(isDragActive && { opacity: 2.72 }),
}}
>
<input {...getInputProps()} />
{/* <Stack
spacing={2}
alignItems="center"
justifyContent="center"
direction={{ xs: 'column', md: 'row' }}
sx={{ width: 1, textAlign: { xs: 'center', md: 'left' } }}
> */}
{image ? (
<img src={URL.createObjectURL(image)} alt="preview" width={220} />
) : currentImage ? (
<img src={currentImage} alt="preview" width={220} />
) : (
<PlaceholderStyle
className="placeholder"
sx={{
...((isDragReject || error) && {
bgcolor: 'error.lighter',
}),
}}
>
<Iconify icon={'ic:round-add-a-photo'} sx={{ width: 24, height: 24, mb: 1 }} />
<Typography variant="caption">{image ? 'Update photo' : 'Upload photo'}</Typography>
</PlaceholderStyle>
)}
<PlaceholderStyle className="placeholder">
<Iconify icon={'ic:round-add-a-photo'} sx={{ width: 24, height: 24, mb: 1 }} />
<Typography variant="caption">{image ? 'Update photo' : 'Upload photo'}</Typography>
</PlaceholderStyle>
{/* </Stack> */}
{/* <BlockContent file={image} /> */}
{isDragReject && <p>Unsupported file type...</p>}
</DropZoneStyle>
</RootStyle>
);
};
export default UploadImage;

View File

@@ -1,10 +1,18 @@
// form // form
import { useFormContext, Controller } from 'react-hook-form'; import { useFormContext, Controller } from 'react-hook-form';
import * as React from 'react';
// @mui // @mui
import { TextField, TextFieldProps } from '@mui/material'; import { IconButton, TextField, TextFieldProps } from '@mui/material';
import { LocalizationProvider, MobileDatePicker } from '@mui/x-date-pickers'; import { LocalizationProvider, MobileDatePicker } from '@mui/x-date-pickers';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'; import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { DesktopDatePicker } from '@mui/x-date-pickers/DesktopDatePicker';
import InputAdornment from '@mui/material/InputAdornment';
import EventIcon from '@mui/icons-material/Event';
import { fPostFormat } from '../../utils/formatTime';
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
interface IProps { interface IProps {
@@ -13,19 +21,43 @@ interface IProps {
export default function RHFDatepicker({ name, ...other }: IProps & TextFieldProps) { export default function RHFDatepicker({ name, ...other }: IProps & TextFieldProps) {
const { control } = useFormContext(); const { control } = useFormContext();
return ( return (
<Controller <Controller
name={name} name={name}
control={control} control={control}
render={({ field, fieldState: { error } }) => ( render={({ field, fieldState: { error } }) => (
<LocalizationProvider dateAdapter={AdapterDateFns}> <LocalizationProvider dateAdapter={AdapterDateFns}>
<MobileDatePicker <MobileDatePicker
inputFormat="yyyy-MM-dd" inputFormat="yyyy-MM-dd"
value={field.value} value={field.value}
onChange={field.onChange} onChange={(value) => {
renderInput={(field) => <TextField {...field} fullWidth error={!!error} helperText={error?.message} {...other} />} field.onChange(fPostFormat(value));
}}
renderInput={(field) => (
<TextField
{...field}
fullWidth
InputProps={{
endAdornment: (
<InputAdornment position="end">
<EventIcon />
</InputAdornment>
),
}}
error={!!error}
helperText={error?.message}
{...other}
/>
)}
/> />
{/* <DesktopDatePicker
value={field.value}
onChange={(value) => {
field.onChange(fPostFormat(value));
}}
renderInput={(params) => <TextField {...params} fullWidth />}
/> */}
</LocalizationProvider> </LocalizationProvider>
)} )}
/> />

View File

@@ -26,7 +26,6 @@ export function RHFUploadAvatar({ name, ...other }: Props) {
control={control} control={control}
render={({ field, fieldState: { error } }) => { render={({ field, fieldState: { error } }) => {
const checkError = !!error && !field.value; const checkError = !!error && !field.value;
return ( return (
<div> <div>
<UploadAvatar error={checkError} {...other} file={field.value} /> <UploadAvatar error={checkError} {...other} file={field.value} />

View File

@@ -42,6 +42,7 @@ import { Corporate } from '../../@types/corporates';
import axios from '../../utils/axios'; import axios from '../../utils/axios';
import { fCurrency } from '../../utils/formatNumber'; import { fCurrency } from '../../utils/formatNumber';
import RHFAutocomplete from '../../components/hook-form/RHFAutocomplete'; import RHFAutocomplete from '../../components/hook-form/RHFAutocomplete';
import UploadImage from '../../components/UploadImage';
const LabelStyle = styled(Typography)(({ theme }) => ({ const LabelStyle = styled(Typography)(({ theme }) => ({
...theme.typography.subtitle2, ...theme.typography.subtitle2,
@@ -61,7 +62,7 @@ type Props = {
export default function CorporateForm({ isEdit, currentCorporate }: Props) { export default function CorporateForm({ isEdit, currentCorporate }: Props) {
const navigate = useNavigate(); const navigate = useNavigate();
const [corporate_groups, setCorporateGroups] = useState([]) const [corporate_groups, setCorporateGroups] = useState([]);
// const [ errors, setErrors ] = useState<{ [key: string]: string }>({}); // const [ errors, setErrors ] = useState<{ [key: string]: string }>({});
@@ -72,10 +73,10 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) {
code: Yup.string().required('Corporate Code is required'), code: Yup.string().required('Corporate Code is required'),
active: Yup.boolean().required('Corporate Status is required'), active: Yup.boolean().required('Corporate Status is required'),
type: Yup.string().required('Type is required'), type: Yup.string().required('Type is required'),
parent_id: Yup.string().when("type", { parent_id: Yup.string().when('type', {
is: 'subcorporate', is: 'subcorporate',
then: Yup.string().required("Corporate is required because type is Sub Corporate") then: Yup.string().required('Corporate is required because type is Sub Corporate'),
}) }),
}); });
const defaultValues = useMemo( const defaultValues = useMemo(
@@ -88,16 +89,20 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) {
policy_id: currentCorporate?.current_policy?.id || '', policy_id: currentCorporate?.current_policy?.id || '',
policy_code: currentCorporate?.current_policy?.code || '', policy_code: currentCorporate?.current_policy?.code || '',
policy_total_premi: currentCorporate?.current_policy?.total_premi || 0, policy_total_premi: currentCorporate?.current_policy?.total_premi || 0,
policy_minimal_deposit_percentage: currentCorporate?.current_policy?.minimal_deposit_percentage || 50, policy_minimal_deposit_percentage:
currentCorporate?.current_policy?.minimal_deposit_percentage || 50,
policy_minimal_deposit_net: currentCorporate?.current_policy?.minimal_deposit_net || 0, policy_minimal_deposit_net: currentCorporate?.current_policy?.minimal_deposit_net || 0,
policy_minimal_alert_percentage: currentCorporate?.current_policy?.minimal_alert_percentage || 25, policy_minimal_alert_percentage:
currentCorporate?.current_policy?.minimal_alert_percentage || 25,
policy_minimal_alert_net: currentCorporate?.current_policy?.minimal_alert_net || 0, policy_minimal_alert_net: currentCorporate?.current_policy?.minimal_alert_net || 0,
policy_stop_service_percentage: currentCorporate?.current_policy?.minimal_stop_service_percentage || 25, policy_stop_service_percentage:
currentCorporate?.current_policy?.minimal_stop_service_percentage || 25,
policy_stop_service_net: currentCorporate?.current_policy?.minimal_stop_service_net || 0, policy_stop_service_net: currentCorporate?.current_policy?.minimal_stop_service_net || 0,
policy_start: currentCorporate?.current_policy?.start || '', policy_start: currentCorporate?.current_policy?.start || '',
policy_end: currentCorporate?.current_policy?.end || '', policy_end: currentCorporate?.current_policy?.end || '',
linking_rules: currentCorporate?.linking_rules || ['nrik', 'nik', 'member_id'], linking_rules: currentCorporate?.linking_rules || ['nrik', 'nik', 'member_id'],
type: currentCorporate?.type || 'corporate' type: currentCorporate?.type || 'corporate',
logo: currentCorporate?.logo || '',
}), }),
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
[currentCorporate] [currentCorporate]
@@ -129,26 +134,57 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) {
reset(defaultValues); reset(defaultValues);
} }
axios.get('/corporates/create') axios
.get('/corporates/create')
.then((res) => { .then((res) => {
setCorporateGroups(res.data.corporate_groups) setCorporateGroups(res.data.corporate_groups);
}) })
.catch((err) => { .catch((err) => {
enqueueSnackbar("Opps, failed to get Corporate Group List", { variant: 'error' }) enqueueSnackbar('Opps, failed to get Corporate Group List', { variant: 'error' });
}) });
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [isEdit, currentCorporate]); }, [isEdit, currentCorporate]);
const currentImage = currentCorporate?.avatar_url;
const [file, setFile] = useState(null);
const [save, setSave] = useState(null);
console.log('save', save);
const onSubmit = async (data: FormValuesProps) => { const onSubmit = async (data: FormValuesProps) => {
try { try {
const formData = new FormData();
formData.append('logo', file);
formData.append('name', data.name);
formData.append('code', data.code);
formData.append('active', data.active ? '1' : '0');
formData.append('type', data.type);
formData.append('welcome_message', data.welcome_message);
formData.append('help_text', data.help_text);
formData.append('policy_id', data.policy_id);
formData.append('policy_code', data.policy_code);
formData.append('policy_total_premi', data.policy_total_premi);
formData.append('policy_minimal_deposit_percentage', data.policy_minimal_deposit_percentage);
formData.append('policy_minimal_deposit_net', data.policy_minimal_deposit_net);
formData.append('policy_minimal_alert_percentage', data.policy_minimal_alert_percentage);
formData.append('policy_minimal_alert_net', data.policy_minimal_alert_net);
formData.append('policy_stop_service_percentage', data.policy_stop_service_percentage);
formData.append('policy_stop_service_net', data.policy_stop_service_net);
formData.append('policy_start', data.policy_start);
formData.append('policy_end', data.policy_end);
formData.append('linking_rules', data.linking_rules);
if (!isEdit) { if (!isEdit) {
const response = await axios.post('/corporates', data); const response = await axios.post('/corporates', formData);
} else { } else {
const response = await axios.put('/corporates/' + currentCorporate?.id ?? '', data); formData.append('_method', 'PUT');
const response = await axios.post(`/corporates/${currentCorporate?.id}`, formData);
} }
reset(); reset();
enqueueSnackbar(!isEdit ? 'Corporate Created Successfully!' : 'Corporate Udpated Successfully!', { variant: 'success' }); enqueueSnackbar(
!isEdit ? 'Corporate Created Successfully!' : 'Corporate Udpated Successfully!',
{ variant: 'success' }
);
navigate('/corporates'); navigate('/corporates');
} catch (error: any) { } catch (error: any) {
if (error && error.response.status === 422) { if (error && error.response.status === 422) {
@@ -156,8 +192,7 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) {
setError(key, { message: value[0] }); setError(key, { message: value[0] });
enqueueSnackbar(value[0] ?? 'Failed Processing Request', { variant: 'error' }); enqueueSnackbar(value[0] ?? 'Failed Processing Request', { variant: 'error' });
} }
} } else {
else {
enqueueSnackbar(error.message ?? 'Failed Processing Request', { variant: 'error' }); enqueueSnackbar(error.message ?? 'Failed Processing Request', { variant: 'error' });
} }
} }
@@ -183,100 +218,103 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) {
// Only Handle Change on Policy Total Premi // Only Handle Change on Policy Total Premi
useEffect(() => { useEffect(() => {
let calc_policy_minimal_deposit_net = values.policy_total_premi * values.policy_minimal_deposit_percentage / 100; let calc_policy_minimal_deposit_net =
(values.policy_total_premi * values.policy_minimal_deposit_percentage) / 100;
setValue('policy_minimal_deposit_net', calc_policy_minimal_deposit_net); setValue('policy_minimal_deposit_net', calc_policy_minimal_deposit_net);
let calc_policy_minimal_alert_net = values.policy_total_premi * values.policy_minimal_alert_percentage / 100; let calc_policy_minimal_alert_net =
(values.policy_total_premi * values.policy_minimal_alert_percentage) / 100;
setValue('policy_minimal_alert_net', calc_policy_minimal_alert_net); setValue('policy_minimal_alert_net', calc_policy_minimal_alert_net);
let calc_policy_stop_service_net =
let calc_policy_stop_service_net = values.policy_total_premi * values.policy_stop_service_percentage / 100; (values.policy_total_premi * values.policy_stop_service_percentage) / 100;
setValue('policy_stop_service_net', calc_policy_stop_service_net); setValue('policy_stop_service_net', calc_policy_stop_service_net);
}, [values.policy_total_premi]); }, [values.policy_total_premi]);
// Only Handle on Change Policy Minimal Deposit // Only Handle on Change Policy Minimal Deposit
const handleMinimalDepositNetChange = (e) => { const handleMinimalDepositNetChange = (e) => {
setValue('policy_minimal_deposit_net', e.target.value); setValue('policy_minimal_deposit_net', e.target.value);
setValue('policy_minimal_deposit_percentage', e.target.value / values.policy_total_premi * 100); setValue(
} 'policy_minimal_deposit_percentage',
(e.target.value / values.policy_total_premi) * 100
);
};
const handleMinimalDepositPercentageChange = (e) => { const handleMinimalDepositPercentageChange = (e) => {
setValue('policy_minimal_deposit_percentage', e.target.value); setValue('policy_minimal_deposit_percentage', e.target.value);
setValue('policy_minimal_deposit_net', values.policy_total_premi * e.target.value / 100); setValue('policy_minimal_deposit_net', (values.policy_total_premi * e.target.value) / 100);
} };
// Only Handle on Change Minimal Alert // Only Handle on Change Minimal Alert
const handleMinimalAlertNetChange = (e) => { const handleMinimalAlertNetChange = (e) => {
setValue('policy_minimal_alert_net', e.target.value); setValue('policy_minimal_alert_net', e.target.value);
setValue('policy_minimal_alert_percentage', e.target.value / values.policy_total_premi * 100); setValue('policy_minimal_alert_percentage', (e.target.value / values.policy_total_premi) * 100);
} };
const handleMinimalAlertPercentageChange = (e) => { const handleMinimalAlertPercentageChange = (e) => {
setValue('policy_minimal_alert_percentage', e.target.value); setValue('policy_minimal_alert_percentage', e.target.value);
setValue('policy_minimal_alert_net', values.policy_total_premi * e.target.value / 100); setValue('policy_minimal_alert_net', (values.policy_total_premi * e.target.value) / 100);
} };
// Only Handle on Change Minimum Stop Service // Only Handle on Change Minimum Stop Service
const handleStopServiceNetChange = (e) => { const handleStopServiceNetChange = (e) => {
setValue('policy_stop_service_net', e.target.value); setValue('policy_stop_service_net', e.target.value);
setValue('policy_stop_service_percentage', e.target.value / values.policy_total_premi * 100); setValue('policy_stop_service_percentage', (e.target.value / values.policy_total_premi) * 100);
} };
const handleStopServicePercentageChange = (e) => { const handleStopServicePercentageChange = (e) => {
setValue('policy_stop_service_percentage', e.target.value); setValue('policy_stop_service_percentage', e.target.value);
setValue('policy_stop_service_net', values.policy_total_premi * e.target.value / 100); setValue('policy_stop_service_net', (values.policy_total_premi * e.target.value) / 100);
} };
const linking_rules_checkbox_name = "linking_rules" const linking_rules_checkbox_name = 'linking_rules';
const linking_tools = [ const linking_tools = [
{ {
"value" : "nrik", value: 'nrik',
"label" : "No. KTP" label: 'No. KTP',
}, },
{ {
"value" : "nik", value: 'nik',
"label" : "Nomor Induk Karyawan (NIK)" label: 'Nomor Induk Karyawan (NIK)',
}, },
{ {
"value" : "member_id", value: 'member_id',
"label" : "Member ID" label: 'Member ID',
}, },
{ {
"value" : "phone", value: 'phone',
"label" : "Nomor Telepon" label: 'Nomor Telepon',
}, },
{ {
"value" : "email", value: 'email',
"label" : "E-Mail" label: 'E-Mail',
}, },
] ];
const types = [ const types = [
{ {
"value" : "corporate", value: 'corporate',
"label" : "Corporate" label: 'Corporate',
}, },
{ {
"value" : "subcorporate", value: 'subcorporate',
"label" : "Sub Corporate" label: 'Sub Corporate',
}, },
] ];
const options = [ const options = [
{ {
"label" : "Something", label: 'Something',
"id" : "Something" id: 'Something',
}, },
{ {
"label" : "Syalalalal", label: 'Syalalalal',
"id" : "Syalalalal" id: 'Syalalalal',
}, },
{ {
"label" : "Lilili", label: 'Lilili',
"id" : "Lilili" id: 'Lilili',
}, },
] ];
const handleTypeChange = (event: SelectChangeEvent) => { const handleTypeChange = (event: SelectChangeEvent) => {
setValue('type', event.target.value) setValue('type', event.target.value);
} };
return ( return (
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}> <FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
@@ -285,7 +323,9 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) {
<Grid item xs={12} md={8}> <Grid item xs={12} md={8}>
<Card sx={{ p: 3 }}> <Card sx={{ p: 3 }}>
<Stack spacing={3}> <Stack spacing={3}>
<Grid item xs={12}><Typography variant='h5'>Corporate Profile</Typography></Grid> <Grid item xs={12}>
<Typography variant="h5">Corporate Profile</Typography>
</Grid>
<RHFSelect name="type" label="Type" placeholder="Type"> <RHFSelect name="type" label="Type" placeholder="Type">
<option value="" /> <option value="" />
@@ -297,28 +337,38 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) {
</RHFSelect> </RHFSelect>
{/* // TODO Use Autocomplete */} {/* // TODO Use Autocomplete */}
{( values.type == 'subcorporate' && <RHFSelect name="parent_id" label="Parent Corporate Group" placeholder="Parent Corporate Group"> {values.type == 'subcorporate' && (
<option value="" /> <RHFSelect
{corporate_groups name="parent_id"
.filter((option) => option.value != values.id) label="Parent Corporate Group"
.map((option, index) => ( placeholder="Parent Corporate Group"
<option key={index} value={option.value}> >
{option.label} <option value="" />
</option> {corporate_groups
))} .filter((option) => option.value != values.id)
</RHFSelect> )} .map((option, index) => (
<option key={index} value={option.value}>
{option.label}
</option>
))}
</RHFSelect>
)}
<RHFTextField name="code" label="Corporate Code" /> <RHFTextField name="code" label="Corporate Code" />
<RHFTextField name="name" label="Corporate Name" /> <RHFTextField name="name" label="Corporate Name" />
<Stack spacing={1}> <Stack spacing={1}>
<Typography variant='subtitle2' sx={{ color: "text.secondary" }}>Welcome Message</Typography> <Typography variant="subtitle2" sx={{ color: 'text.secondary' }}>
Welcome Message
</Typography>
<RHFEditor name="welcome_message" /> <RHFEditor name="welcome_message" />
</Stack> </Stack>
<Stack spacing={1}> <Stack spacing={1}>
<Typography variant='subtitle2' sx={{ color: "text.secondary" }}>Help Text</Typography> <Typography variant="subtitle2" sx={{ color: 'text.secondary' }}>
Help Text
</Typography>
<RHFEditor name="help_text" /> <RHFEditor name="help_text" />
</Stack> </Stack>
@@ -342,103 +392,149 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) {
<Grid item xs={12} md={4}> <Grid item xs={12} md={4}>
<Stack spacing={3}> <Stack spacing={3}>
<Card sx={{ p: 3 }}> <Card sx={{ p: 3 }}>
{ JSON.stringify(values.active) } {JSON.stringify(values.active)}
<RHFSwitch name="active" label="Is Company Active" /> <RHFSwitch name="active" label="Is Company Active" />
<Stack spacing={3} mt={2}> <Stack spacing={3} mt={2} alignItems="center">
<Typography align="center">Company Logo</Typography> <Typography align="center">Company Logo</Typography>
<RHFUploadAvatar name="logo" {/* <RHFUploadAvatar
name="logo"
showPreview showPreview
accept={'image/*'} accept="image/*"
maxSize={3145728} maxSize={3145728}
onDrop={handleDrop} onDrop={handleDrop}
onRemove={handleRemove} onRemove={handleRemove}
/> /> */}
<UploadImage setFile={setFile} currentImage={currentImage} />
</Stack> </Stack>
</Card> </Card>
<Card sx={{ p: 3 }}> <Card sx={{ p: 3 }}>
<Stack> <Stack>
<Typography variant='subtitle2' sx={{ color: "text.secondary" }}>Linking Rules</Typography> <Typography variant="subtitle2" sx={{ color: 'text.secondary' }}>
Linking Rules
</Typography>
<Stack> <Stack>
<RHFCustomMultiCheckbox name='linking_rules' options={linking_tools} /> <RHFCustomMultiCheckbox name="linking_rules" options={linking_tools} />
</Stack> </Stack>
</Stack> </Stack>
</Card> </Card>
</Stack> </Stack>
</Grid> </Grid>
{( values.type == 'corporate' && <Grid item xs={12} md={12}> {values.type == 'corporate' && (
{/* <Card sx={{ p:3, mb:3, background: 'gray', color: 'white' }}><Typography>Policy Detail</Typography></Card> */} <Grid item xs={12} md={12}>
<Card sx={{ p: 3 }}> {/* <Card sx={{ p:3, mb:3, background: 'gray', color: 'white' }}><Typography>Policy Detail</Typography></Card> */}
<Stack spacing={3} mt={2}> <Card sx={{ p: 3 }}>
<Stack spacing={3} mt={2}>
<Grid item xs={12}><Typography variant='h5'>Policy Detail</Typography></Grid> <Grid item xs={12}>
<Typography variant="h5">Policy Detail</Typography>
<input type="hidden" name="policy_id" />
<Stack spacing={1}>
<RHFTextField name="policy_code" label="Policy Number" />
{(!(currentCorporate?.id) && <Typography variant="caption">Will be generated if empty</Typography>)}
</Stack>
{/* <Typography>Minimal Deposit Policy Level</Typography> */}
<Stack direction="row" spacing={2}>
<Grid item xs={12} md={6}>
<RHFDatepicker name="policy_start" label="Start Date (YYYY-MM-DD)" />
</Grid> </Grid>
<Grid item xs={12} md={6}>
<RHFDatepicker name="policy_end" label="End Date (YYYY-MM-DD)" />
</Grid>
</Stack>
<RHFTextField name="policy_total_premi" label={"Deposit Intial Fund ("+fCurrency(values.policy_total_premi)+")"}/> <input type="hidden" name="policy_id" />
<Stack spacing={1}> <Stack spacing={1}>
<Typography variant='subtitle2' sx={{ color: "text.secondary" }}>Minimal Deposit Policy Level</Typography> <RHFTextField name="policy_code" label="Policy Number" />
<Grid container> {!currentCorporate?.id && (
<Grid item xs={12} md={3}> <Typography variant="caption">Will be generated if empty</Typography>
<RHFTextField name="policy_minimal_deposit_percentage" label="Percentage (%)" onChange={handleMinimalDepositPercentageChange}/> )}
</Stack>
{/* <Typography>Minimal Deposit Policy Level</Typography> */}
<Stack direction="row" spacing={2}>
<Grid item xs={12} md={6}>
<RHFDatepicker name="policy_start" label="Start Date (YYYY-MM-DD)" />
</Grid> </Grid>
<Grid item xs={12} md={9}> <Grid item xs={12} md={6}>
<RHFTextField name="policy_minimal_deposit_net" label={"Net ("+fCurrency(values.policy_minimal_deposit_net)+")"} onChange={handleMinimalDepositNetChange}/> <RHFDatepicker name="policy_end" label="End Date (YYYY-MM-DD)" />
</Grid> </Grid>
</Grid> </Stack>
</Stack>
<Stack spacing={1}> <RHFTextField
<Typography variant='subtitle2' sx={{ color: "text.secondary" }}>Minimal Alert Level</Typography> name="policy_total_premi"
<Grid container> label={'Deposit Intial Fund (' + fCurrency(values.policy_total_premi) + ')'}
<Grid item xs={12} md={3}> />
<RHFTextField name="policy_minimal_alert_percentage" label="Percentage (%)" onChange={handleMinimalAlertPercentageChange}/>
</Grid>
<Grid item xs={12} md={9}>
<RHFTextField name="policy_minimal_alert_net" label={"Net ("+fCurrency(values.policy_minimal_alert_net)+")"} onChange={handleMinimalAlertNetChange}/>
</Grid>
</Grid>
</Stack>
<Stack spacing={1}> <Stack spacing={1}>
<Typography variant='subtitle2' sx={{ color: "text.secondary" }}>Stop Service Level</Typography> <Typography variant="subtitle2" sx={{ color: 'text.secondary' }}>
<Grid container> Minimal Deposit Policy Level
<Grid item xs={12} md={3}> </Typography>
<RHFTextField name="policy_stop_service_percentage" label="Percentage (%)" onChange={handleStopServicePercentageChange}/> <Grid container>
</Grid> <Grid item xs={12} md={3}>
<Grid item xs={12} md={9}> <RHFTextField
<RHFTextField name="policy_stop_service_net" label={"Net ("+fCurrency(values.policy_stop_service_net)+")"} onChange={handleStopServiceNetChange}/> name="policy_minimal_deposit_percentage"
</Grid> label="Percentage (%)"
</Grid> onChange={handleMinimalDepositPercentageChange}
</Stack> />
</Grid>
<Grid item xs={12} md={9}>
<RHFTextField
name="policy_minimal_deposit_net"
label={'Net (' + fCurrency(values.policy_minimal_deposit_net) + ')'}
onChange={handleMinimalDepositNetChange}
/>
</Grid>
</Grid>
</Stack>
</Stack> <Stack spacing={1}>
</Card> <Typography variant="subtitle2" sx={{ color: 'text.secondary' }}>
</Grid> )} Minimal Alert Level
</Typography>
<Grid container>
<Grid item xs={12} md={3}>
<RHFTextField
name="policy_minimal_alert_percentage"
label="Percentage (%)"
onChange={handleMinimalAlertPercentageChange}
/>
</Grid>
<Grid item xs={12} md={9}>
<RHFTextField
name="policy_minimal_alert_net"
label={'Net (' + fCurrency(values.policy_minimal_alert_net) + ')'}
onChange={handleMinimalAlertNetChange}
/>
</Grid>
</Grid>
</Stack>
<Stack spacing={1}>
<Typography variant="subtitle2" sx={{ color: 'text.secondary' }}>
Stop Service Level
</Typography>
<Grid container>
<Grid item xs={12} md={3}>
<RHFTextField
name="policy_stop_service_percentage"
label="Percentage (%)"
onChange={handleStopServicePercentageChange}
/>
</Grid>
<Grid item xs={12} md={9}>
<RHFTextField
name="policy_stop_service_net"
label={'Net (' + fCurrency(values.policy_stop_service_net) + ')'}
onChange={handleStopServiceNetChange}
/>
</Grid>
</Grid>
</Stack>
</Stack>
</Card>
</Grid>
)}
<Grid item xs={12} md={4}> <Grid item xs={12} md={4}>
<LoadingButton type="submit" variant="contained" size="large" fullWidth={true} loading={isSubmitting}> <LoadingButton
type="submit"
variant="contained"
size="large"
fullWidth={true}
loading={isSubmitting}
>
{!isEdit ? 'Save New Corporate' : 'Save Corporate'} {!isEdit ? 'Save New Corporate' : 'Save Corporate'}
</LoadingButton> </LoadingButton>
</Grid> </Grid>
</Grid> </Grid>
</FormProvider> </FormProvider>
); );
}; }

View File

@@ -23,3 +23,8 @@ export function fToNow(date: Date | string | number) {
addSuffix: true addSuffix: true
}); });
} }
export function fPostFormat(date: Date | string | number) {
return format(new Date(date), 'yyyy-MM-dd HH:mm:ss');
}