upload foto, dan bugs import
This commit is contained in:
@@ -18,6 +18,8 @@ use Illuminate\Http\Request;
|
||||
use Illuminate\Routing\Controller;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use Box\Spout\Reader\Common\Creator\ReaderEntityFactory;
|
||||
use App\Models\File;
|
||||
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Modules\Internal\Services\CorporateService;
|
||||
|
||||
@@ -220,6 +222,18 @@ class CorporateController extends Controller
|
||||
$managerOne = User::where('email', 'manager+one@gmail.com')->first();
|
||||
$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();
|
||||
} catch (\Exception $e) {
|
||||
@@ -282,9 +296,13 @@ class CorporateController extends Controller
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
//karena pake formdata
|
||||
$linkingRules = $request->linking_rules;
|
||||
$linkingRules = explode(',', $linkingRules);
|
||||
|
||||
$corporate = Corporate::findOrFail($id);
|
||||
$corporate->fill($request->toArray());
|
||||
$corporate->fill($request->all());
|
||||
$corporate->linking_rules = $linkingRules;
|
||||
$corporate->save();
|
||||
|
||||
$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();
|
||||
} catch (\Exception $e) {
|
||||
DB::rollBack();
|
||||
|
||||
@@ -10,7 +10,7 @@ use App\Models\Plan;
|
||||
use Box\Spout\Writer\Common\Creator\WriterEntityFactory;
|
||||
|
||||
class CorporateService
|
||||
{
|
||||
{
|
||||
protected function validatePlanRow($row)
|
||||
{
|
||||
if (empty($row['service_code'])) {
|
||||
@@ -84,12 +84,16 @@ class CorporateService
|
||||
|
||||
public function handleBenefitRow(Corporate $corporate, $row)
|
||||
{
|
||||
|
||||
try {
|
||||
$benefit_data = $row;
|
||||
$benefit_data["corporate_id"] = $corporate->id;
|
||||
$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 = Benefit::updateOrCreate([
|
||||
@@ -104,11 +108,11 @@ class CorporateService
|
||||
$corporateBenefit = $corporate->corporateBenefits()->updateOrCreate([
|
||||
'benefit_id' => $benefit->id,
|
||||
'plan_id' => $plan->id
|
||||
], $benefit_data );
|
||||
], $benefit_data);
|
||||
|
||||
return $corporateBenefit;
|
||||
} catch (\Exception $e) {
|
||||
dd($e->getMessage());
|
||||
// dd($e->getMessage());
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,8 +362,8 @@ class MemberEnrollmentService
|
||||
"nik" => $row['nik'] ?? null,
|
||||
"birth_date" => Carbon::parse(strtotime($row['date_of_birth'])),
|
||||
"gender" => Helper::genderNormalization($row['sex']),
|
||||
"language" => $row['language'] ?? null,
|
||||
"race" => $row['race'] ?? null,
|
||||
// "language" => $row['language'] ?? null,
|
||||
// "race" => $row['race'] ?? null,
|
||||
"marital_status" => $row['marital_status'] ?? null,
|
||||
"record_type" => $row['record_type'] ?? null,
|
||||
"principal_id" => $row['principal_id'] ?? null,
|
||||
@@ -429,15 +429,6 @@ class MemberEnrollmentService
|
||||
]), 0, null, $row);
|
||||
} else {
|
||||
$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()
|
||||
@@ -463,10 +454,22 @@ class MemberEnrollmentService
|
||||
|
||||
$this->validateRow($row);
|
||||
|
||||
|
||||
try {
|
||||
DB::beginTransaction();
|
||||
$member->fill($member_data);
|
||||
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->fill([
|
||||
'member_id' => $member->member_id,
|
||||
|
||||
@@ -8,10 +8,10 @@ use Throwable;
|
||||
class ImportRowException extends Exception
|
||||
{
|
||||
protected $data = null;
|
||||
|
||||
|
||||
public function __construct($message, $code = 0, Throwable $previous = null, $data)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
parent::__construct($message, (int)$code, $previous);
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,10 @@ class Corporate extends Model
|
||||
'linking_rules' => 'array',
|
||||
];
|
||||
|
||||
protected $appends = [
|
||||
'avatar_url',
|
||||
];
|
||||
|
||||
public function imports()
|
||||
{
|
||||
return $this->morphMany(ImportLog::class, 'importable');
|
||||
@@ -36,6 +40,16 @@ class Corporate extends Model
|
||||
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()
|
||||
{
|
||||
return $this->hasMany(Plan::class, 'corporate_id', 'id');
|
||||
|
||||
@@ -22,6 +22,8 @@ class Person extends Model
|
||||
'gender',
|
||||
'birth_date',
|
||||
'birth_place',
|
||||
'language',
|
||||
'race',
|
||||
'citizenship',
|
||||
'current_employment',
|
||||
'last_education',
|
||||
|
||||
93
frontend/dashboard/src/components/MyDropzone.tsx
Normal file
93
frontend/dashboard/src/components/MyDropzone.tsx
Normal 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
|
||||
<Typography
|
||||
variant="body2"
|
||||
component="span"
|
||||
sx={{ color: 'primary.main', textDecoration: 'underline' }}
|
||||
>
|
||||
jelajahi
|
||||
</Typography>
|
||||
foto di perangkat Anda
|
||||
</Typography>
|
||||
</Box>
|
||||
</Stack>
|
||||
{/* <BlockContent file={image} /> */}
|
||||
|
||||
{isDragReject && <p>Unsupported file type...</p>}
|
||||
</DropZoneStyle>
|
||||
);
|
||||
};
|
||||
|
||||
export default MyDropzone;
|
||||
128
frontend/dashboard/src/components/UploadImage.tsx
Normal file
128
frontend/dashboard/src/components/UploadImage.tsx
Normal 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;
|
||||
@@ -1,10 +1,18 @@
|
||||
// form
|
||||
import { useFormContext, Controller } from 'react-hook-form';
|
||||
import * as React from 'react';
|
||||
|
||||
// @mui
|
||||
import { TextField, TextFieldProps } from '@mui/material';
|
||||
import { IconButton, TextField, TextFieldProps } from '@mui/material';
|
||||
import { LocalizationProvider, MobileDatePicker } from '@mui/x-date-pickers';
|
||||
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 {
|
||||
@@ -13,19 +21,43 @@ interface IProps {
|
||||
|
||||
export default function RHFDatepicker({ name, ...other }: IProps & TextFieldProps) {
|
||||
const { control } = useFormContext();
|
||||
|
||||
return (
|
||||
<Controller
|
||||
name={name}
|
||||
control={control}
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
|
||||
<LocalizationProvider dateAdapter={AdapterDateFns}>
|
||||
<MobileDatePicker
|
||||
inputFormat="yyyy-MM-dd"
|
||||
value={field.value}
|
||||
onChange={field.onChange}
|
||||
renderInput={(field) => <TextField {...field} fullWidth error={!!error} helperText={error?.message} {...other} />}
|
||||
onChange={(value) => {
|
||||
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>
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -26,7 +26,6 @@ export function RHFUploadAvatar({ name, ...other }: Props) {
|
||||
control={control}
|
||||
render={({ field, fieldState: { error } }) => {
|
||||
const checkError = !!error && !field.value;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<UploadAvatar error={checkError} {...other} file={field.value} />
|
||||
|
||||
@@ -42,6 +42,7 @@ import { Corporate } from '../../@types/corporates';
|
||||
import axios from '../../utils/axios';
|
||||
import { fCurrency } from '../../utils/formatNumber';
|
||||
import RHFAutocomplete from '../../components/hook-form/RHFAutocomplete';
|
||||
import UploadImage from '../../components/UploadImage';
|
||||
|
||||
const LabelStyle = styled(Typography)(({ theme }) => ({
|
||||
...theme.typography.subtitle2,
|
||||
@@ -61,7 +62,7 @@ type Props = {
|
||||
|
||||
export default function CorporateForm({ isEdit, currentCorporate }: Props) {
|
||||
const navigate = useNavigate();
|
||||
const [corporate_groups, setCorporateGroups] = useState([])
|
||||
const [corporate_groups, setCorporateGroups] = useState([]);
|
||||
|
||||
// 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'),
|
||||
active: Yup.boolean().required('Corporate Status is required'),
|
||||
type: Yup.string().required('Type is required'),
|
||||
parent_id: Yup.string().when("type", {
|
||||
parent_id: Yup.string().when('type', {
|
||||
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(
|
||||
@@ -88,16 +89,20 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) {
|
||||
policy_id: currentCorporate?.current_policy?.id || '',
|
||||
policy_code: currentCorporate?.current_policy?.code || '',
|
||||
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_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_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_start: currentCorporate?.current_policy?.start || '',
|
||||
policy_end: currentCorporate?.current_policy?.end || '',
|
||||
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
|
||||
[currentCorporate]
|
||||
@@ -129,35 +134,65 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) {
|
||||
reset(defaultValues);
|
||||
}
|
||||
|
||||
axios.get('/corporates/create')
|
||||
axios
|
||||
.get('/corporates/create')
|
||||
.then((res) => {
|
||||
setCorporateGroups(res.data.corporate_groups)
|
||||
setCorporateGroups(res.data.corporate_groups);
|
||||
})
|
||||
.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
|
||||
}, [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) => {
|
||||
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) {
|
||||
const response = await axios.post('/corporates', data);
|
||||
const response = await axios.post('/corporates', formData);
|
||||
} else {
|
||||
const response = await axios.put('/corporates/' + currentCorporate?.id ?? '', data);
|
||||
formData.append('_method', 'PUT');
|
||||
const response = await axios.post(`/corporates/${currentCorporate?.id}`, formData);
|
||||
}
|
||||
reset();
|
||||
enqueueSnackbar(!isEdit ? 'Corporate Created Successfully!' : 'Corporate Udpated Successfully!', { variant: 'success' });
|
||||
enqueueSnackbar(
|
||||
!isEdit ? 'Corporate Created Successfully!' : 'Corporate Udpated Successfully!',
|
||||
{ variant: 'success' }
|
||||
);
|
||||
navigate('/corporates');
|
||||
} catch (error: any) {
|
||||
if (error && error.response.status === 422) {
|
||||
for (const [key, value] of Object.entries(error.response.data.errors)) {
|
||||
for (const [key, value] of Object.entries(error.response.data.errors)) {
|
||||
setError(key, { message: value[0] });
|
||||
enqueueSnackbar(value[0] ?? 'Failed Processing Request', { variant: 'error' });
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
|
||||
let calc_policy_stop_service_net = values.policy_total_premi * values.policy_stop_service_percentage / 100;
|
||||
let calc_policy_stop_service_net =
|
||||
(values.policy_total_premi * values.policy_stop_service_percentage) / 100;
|
||||
setValue('policy_stop_service_net', calc_policy_stop_service_net);
|
||||
|
||||
}, [values.policy_total_premi]);
|
||||
|
||||
// Only Handle on Change Policy Minimal Deposit
|
||||
const handleMinimalDepositNetChange = (e) => {
|
||||
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) => {
|
||||
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
|
||||
const handleMinimalAlertNetChange = (e) => {
|
||||
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) => {
|
||||
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
|
||||
const handleStopServiceNetChange = (e) => {
|
||||
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) => {
|
||||
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 = [
|
||||
{
|
||||
"value" : "nrik",
|
||||
"label" : "No. KTP"
|
||||
value: 'nrik',
|
||||
label: 'No. KTP',
|
||||
},
|
||||
{
|
||||
"value" : "nik",
|
||||
"label" : "Nomor Induk Karyawan (NIK)"
|
||||
value: 'nik',
|
||||
label: 'Nomor Induk Karyawan (NIK)',
|
||||
},
|
||||
{
|
||||
"value" : "member_id",
|
||||
"label" : "Member ID"
|
||||
value: 'member_id',
|
||||
label: 'Member ID',
|
||||
},
|
||||
{
|
||||
"value" : "phone",
|
||||
"label" : "Nomor Telepon"
|
||||
value: 'phone',
|
||||
label: 'Nomor Telepon',
|
||||
},
|
||||
{
|
||||
"value" : "email",
|
||||
"label" : "E-Mail"
|
||||
value: 'email',
|
||||
label: 'E-Mail',
|
||||
},
|
||||
]
|
||||
];
|
||||
|
||||
const types = [
|
||||
{
|
||||
"value" : "corporate",
|
||||
"label" : "Corporate"
|
||||
value: 'corporate',
|
||||
label: 'Corporate',
|
||||
},
|
||||
{
|
||||
"value" : "subcorporate",
|
||||
"label" : "Sub Corporate"
|
||||
value: 'subcorporate',
|
||||
label: 'Sub Corporate',
|
||||
},
|
||||
]
|
||||
];
|
||||
|
||||
const options = [
|
||||
{
|
||||
"label" : "Something",
|
||||
"id" : "Something"
|
||||
label: 'Something',
|
||||
id: 'Something',
|
||||
},
|
||||
{
|
||||
"label" : "Syalalalal",
|
||||
"id" : "Syalalalal"
|
||||
label: 'Syalalalal',
|
||||
id: 'Syalalalal',
|
||||
},
|
||||
{
|
||||
"label" : "Lilili",
|
||||
"id" : "Lilili"
|
||||
label: 'Lilili',
|
||||
id: 'Lilili',
|
||||
},
|
||||
]
|
||||
];
|
||||
|
||||
const handleTypeChange = (event: SelectChangeEvent) => {
|
||||
setValue('type', event.target.value)
|
||||
}
|
||||
|
||||
setValue('type', event.target.value);
|
||||
};
|
||||
|
||||
return (
|
||||
<FormProvider methods={methods} onSubmit={handleSubmit(onSubmit)}>
|
||||
@@ -285,7 +323,9 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) {
|
||||
<Grid item xs={12} md={8}>
|
||||
<Card sx={{ p: 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">
|
||||
<option value="" />
|
||||
@@ -295,30 +335,40 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) {
|
||||
</option>
|
||||
))}
|
||||
</RHFSelect>
|
||||
|
||||
|
||||
{/* // TODO Use Autocomplete */}
|
||||
{( values.type == 'subcorporate' && <RHFSelect name="parent_id" label="Parent Corporate Group" placeholder="Parent Corporate Group">
|
||||
<option value="" />
|
||||
{corporate_groups
|
||||
.filter((option) => option.value != values.id)
|
||||
.map((option, index) => (
|
||||
<option key={index} value={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</RHFSelect> )}
|
||||
|
||||
{values.type == 'subcorporate' && (
|
||||
<RHFSelect
|
||||
name="parent_id"
|
||||
label="Parent Corporate Group"
|
||||
placeholder="Parent Corporate Group"
|
||||
>
|
||||
<option value="" />
|
||||
{corporate_groups
|
||||
.filter((option) => option.value != values.id)
|
||||
.map((option, index) => (
|
||||
<option key={index} value={option.value}>
|
||||
{option.label}
|
||||
</option>
|
||||
))}
|
||||
</RHFSelect>
|
||||
)}
|
||||
|
||||
<RHFTextField name="code" label="Corporate Code" />
|
||||
|
||||
<RHFTextField name="name" label="Corporate Name" />
|
||||
|
||||
<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" />
|
||||
</Stack>
|
||||
|
||||
<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" />
|
||||
</Stack>
|
||||
|
||||
@@ -342,103 +392,149 @@ export default function CorporateForm({ isEdit, currentCorporate }: Props) {
|
||||
<Grid item xs={12} md={4}>
|
||||
<Stack spacing={3}>
|
||||
<Card sx={{ p: 3 }}>
|
||||
{ JSON.stringify(values.active) }
|
||||
{JSON.stringify(values.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>
|
||||
<RHFUploadAvatar name="logo"
|
||||
{/* <RHFUploadAvatar
|
||||
name="logo"
|
||||
showPreview
|
||||
accept={'image/*'}
|
||||
accept="image/*"
|
||||
maxSize={3145728}
|
||||
onDrop={handleDrop}
|
||||
onRemove={handleRemove}
|
||||
/>
|
||||
/> */}
|
||||
<UploadImage setFile={setFile} currentImage={currentImage} />
|
||||
</Stack>
|
||||
</Card>
|
||||
<Card sx={{ p: 3 }}>
|
||||
<Stack>
|
||||
<Typography variant='subtitle2' sx={{ color: "text.secondary" }}>Linking Rules</Typography>
|
||||
<Stack>
|
||||
<RHFCustomMultiCheckbox name='linking_rules' options={linking_tools} />
|
||||
<Typography variant="subtitle2" sx={{ color: 'text.secondary' }}>
|
||||
Linking Rules
|
||||
</Typography>
|
||||
<Stack>
|
||||
<RHFCustomMultiCheckbox name="linking_rules" options={linking_tools} />
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Card>
|
||||
</Stack>
|
||||
</Grid>
|
||||
|
||||
{( values.type == 'corporate' && <Grid item xs={12} md={12}>
|
||||
{/* <Card sx={{ p:3, mb:3, background: 'gray', color: 'white' }}><Typography>Policy Detail</Typography></Card> */}
|
||||
<Card sx={{ p: 3 }}>
|
||||
<Stack spacing={3} mt={2}>
|
||||
|
||||
<Grid item xs={12}><Typography variant='h5'>Policy Detail</Typography></Grid>
|
||||
|
||||
<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)" />
|
||||
{values.type == 'corporate' && (
|
||||
<Grid item xs={12} md={12}>
|
||||
{/* <Card sx={{ p:3, mb:3, background: 'gray', color: 'white' }}><Typography>Policy Detail</Typography></Card> */}
|
||||
<Card sx={{ p: 3 }}>
|
||||
<Stack spacing={3} mt={2}>
|
||||
<Grid item xs={12}>
|
||||
<Typography variant="h5">Policy Detail</Typography>
|
||||
</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}>
|
||||
<Typography variant='subtitle2' sx={{ color: "text.secondary" }}>Minimal Deposit Policy Level</Typography>
|
||||
<Grid container>
|
||||
<Grid item xs={12} md={3}>
|
||||
<RHFTextField name="policy_minimal_deposit_percentage" label="Percentage (%)" onChange={handleMinimalDepositPercentageChange}/>
|
||||
<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 item xs={12} md={9}>
|
||||
<RHFTextField name="policy_minimal_deposit_net" label={"Net ("+fCurrency(values.policy_minimal_deposit_net)+")"} onChange={handleMinimalDepositNetChange}/>
|
||||
<Grid item xs={12} md={6}>
|
||||
<RHFDatepicker name="policy_end" label="End Date (YYYY-MM-DD)" />
|
||||
</Grid>
|
||||
</Grid>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
<Stack spacing={1}>
|
||||
<Typography variant='subtitle2' sx={{ color: "text.secondary" }}>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>
|
||||
<RHFTextField
|
||||
name="policy_total_premi"
|
||||
label={'Deposit Intial Fund (' + fCurrency(values.policy_total_premi) + ')'}
|
||||
/>
|
||||
|
||||
<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 spacing={1}>
|
||||
<Typography variant="subtitle2" sx={{ color: 'text.secondary' }}>
|
||||
Minimal Deposit Policy Level
|
||||
</Typography>
|
||||
<Grid container>
|
||||
<Grid item xs={12} md={3}>
|
||||
<RHFTextField
|
||||
name="policy_minimal_deposit_percentage"
|
||||
label="Percentage (%)"
|
||||
onChange={handleMinimalDepositPercentageChange}
|
||||
/>
|
||||
</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 spacing={1}>
|
||||
<Typography variant="subtitle2" sx={{ color: 'text.secondary' }}>
|
||||
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>
|
||||
|
||||
</Stack>
|
||||
</Card>
|
||||
</Grid> )}
|
||||
|
||||
</Card>
|
||||
</Grid>
|
||||
)}
|
||||
|
||||
<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'}
|
||||
</LoadingButton>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
</FormProvider>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -23,3 +23,8 @@ export function fToNow(date: Date | string | number) {
|
||||
addSuffix: true
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function fPostFormat(date: Date | string | number) {
|
||||
return format(new Date(date), 'yyyy-MM-dd HH:mm:ss');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user