update
This commit is contained in:
186
src/pages/settings/user/manage-position/blocks/AddDialog.tsx
Normal file
186
src/pages/settings/user/manage-position/blocks/AddDialog.tsx
Normal file
@ -0,0 +1,186 @@
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
|
||||
import {
|
||||
Dialog,
|
||||
DialogBody,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle
|
||||
} from '@/components/ui/dialog';
|
||||
import { useManagePositionContext } from '../hooks';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { apiConfig } from '@/config/api.config';
|
||||
import { Alert, useDataGrid } from '@/components';
|
||||
import { toast } from 'sonner';
|
||||
import { useCallApi } from '@/hooks';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { doSaveLogActivity } from '@/actions/GlobalActions';
|
||||
|
||||
const API_URL = apiConfig.service_dashboard;
|
||||
|
||||
interface MenuItem {
|
||||
id: string;
|
||||
name: string;
|
||||
children?: MenuItem[];
|
||||
}
|
||||
|
||||
const MenuItemComponent: React.FC<{
|
||||
menu: MenuItem;
|
||||
selectMenus: string[];
|
||||
handleCheckboxChange: (id: string) => void;
|
||||
}> = ({ menu, selectMenus, handleCheckboxChange }) => {
|
||||
const { id, name, children = [] } = menu;
|
||||
|
||||
return (
|
||||
<div className="mt-3">
|
||||
<div className="text-sm flex items-center gap-3">
|
||||
<Checkbox
|
||||
checked={selectMenus.includes(id)}
|
||||
id={`label-${id}`}
|
||||
onCheckedChange={() => handleCheckboxChange(id)}
|
||||
/>
|
||||
<label htmlFor={`label-${id}`}>{name}</label>
|
||||
</div>
|
||||
{children.length > 0 && (
|
||||
<div className="pl-5">
|
||||
{children.map((child) => (
|
||||
<MenuItemComponent
|
||||
key={child.id}
|
||||
menu={child}
|
||||
selectMenus={selectMenus}
|
||||
handleCheckboxChange={handleCheckboxChange}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const AddDialog = () => {
|
||||
const parentRef = useRef<any | null>(null);
|
||||
const { showAddDialog, handleAddDialog, menus } = useManagePositionContext();
|
||||
const { reload } = useDataGrid();
|
||||
const { PostData } = useCallApi();
|
||||
const [alert, setAlert] = useState({
|
||||
show: false,
|
||||
message: ''
|
||||
});
|
||||
const [selectMenus, setSelectMenus] = useState<string[]>([]);
|
||||
const [formField, setFormField] = useState({
|
||||
name: ''
|
||||
});
|
||||
|
||||
/* actions */
|
||||
const handleCheckboxChange = useCallback((key: string) => {
|
||||
setSelectMenus((prev) =>
|
||||
prev.includes(key) ? prev.filter((item) => item !== key) : [...prev, key]
|
||||
);
|
||||
}, []);
|
||||
|
||||
const doCreatePosition = useCallback(
|
||||
async (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
const response = await PostData(`${API_URL}/user_role/create`, {
|
||||
name: formField.name,
|
||||
roles: selectMenus,
|
||||
status: 'Y',
|
||||
application: 'ukln'
|
||||
});
|
||||
|
||||
if (response?.status) {
|
||||
setAlert((prev) => ({ ...prev, show: false, message: '' }));
|
||||
handleAddDialog(false);
|
||||
toast.success('Success Create Position');
|
||||
reload();
|
||||
const createActivity = {
|
||||
module: 'Manage Position',
|
||||
description: `Create New User => ${formField.name}`,
|
||||
action: 'C'
|
||||
};
|
||||
|
||||
doSaveLogActivity(createActivity);
|
||||
} else {
|
||||
setAlert((prev) => ({ ...prev, show: true, message: response?.message }));
|
||||
}
|
||||
},
|
||||
[formField, selectMenus]
|
||||
);
|
||||
|
||||
return (
|
||||
<Dialog open={showAddDialog} onOpenChange={(open) => handleAddDialog(open)}>
|
||||
<DialogContent className="container-fixed max-w-screen-lg flex flex-col p-10 overflow-hidden [&>button]:hidden">
|
||||
<DialogHeader className="p-0 border-0">
|
||||
<DialogTitle></DialogTitle>
|
||||
<DialogDescription></DialogDescription>
|
||||
<div className="flex items-center justify-between flex-wrap grow gap-5 pb-7.5">
|
||||
<div className="flex flex-col justify-center gap-2">
|
||||
<h1 className="text-xl font-semibold leading-none text-gray-900">
|
||||
Positions - Create
|
||||
</h1>
|
||||
<div className="flex items-center gap-2 text-sm font-normal text-gray-700"></div>
|
||||
</div>
|
||||
<Button
|
||||
variant={'outline'}
|
||||
color="#ddd"
|
||||
size={'sm'}
|
||||
onClick={() => handleAddDialog(false)}
|
||||
>
|
||||
Close
|
||||
</Button>
|
||||
</div>
|
||||
</DialogHeader>
|
||||
<DialogBody className="scrollable-y py-0 mb-5 ps-0 pe-3 -me-7" ref={parentRef}>
|
||||
<div className="flex flex-col items-stretch grow gap-5 lg:gap-7.5">
|
||||
{alert.show && (
|
||||
<Alert variant="danger">
|
||||
<h3>{alert.message}</h3>
|
||||
</Alert>
|
||||
)}
|
||||
<form action="" onSubmit={doCreatePosition}>
|
||||
<div className="card-body grid gap-5">
|
||||
<div className="w-full">
|
||||
<div className="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
|
||||
<label className="form-label flex items-center gap-1 max-w-56">Name</label>
|
||||
<Input
|
||||
className="input"
|
||||
type="text"
|
||||
value={formField.name}
|
||||
onChange={({ target }) =>
|
||||
setFormField((prev) => ({ ...prev, name: target.value }))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-3 w-full gap-5">
|
||||
{menus.map((menu) => (
|
||||
<div className="card" key={menu.id}>
|
||||
<div className="card-body">
|
||||
<MenuItemComponent
|
||||
menu={menu}
|
||||
selectMenus={selectMenus}
|
||||
handleCheckboxChange={handleCheckboxChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end pt-2.5">
|
||||
<Button className="btn btn-primary" type="submit">
|
||||
Save Changes
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</DialogBody>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export { AddDialog };
|
||||
@ -0,0 +1,97 @@
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle
|
||||
} from '@/components/ui/dialog';
|
||||
import { useManagePositionContext } from '../hooks';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Alert, useDataGrid } from '@/components';
|
||||
import { ChangeEvent, useCallback, useState } from 'react';
|
||||
import { apiConfig } from '@/config/api.config';
|
||||
import { toast } from 'sonner';
|
||||
import { useCallApi } from '@/hooks';
|
||||
import { doSaveLogActivity } from '@/actions/GlobalActions';
|
||||
import { EnforceSwitch } from '@/components/switch';
|
||||
|
||||
const API_URL = apiConfig.service_dashboard;
|
||||
|
||||
const DeleteDialog = () => {
|
||||
const { showDeleteDialog, handleDeleteDialog, selectedPosition } = useManagePositionContext();
|
||||
const { reload } = useDataGrid();
|
||||
const [enforce, setEnforce] = useState(false);
|
||||
|
||||
const { DeleteData } = useCallApi();
|
||||
const [alert, setAlert] = useState({
|
||||
show: false,
|
||||
message: ''
|
||||
});
|
||||
|
||||
/* actions */
|
||||
const doDeleteData = useCallback(async () => {
|
||||
if (!selectedPosition) {
|
||||
toast.success('Please Select Position');
|
||||
return;
|
||||
}
|
||||
const response = await DeleteData(
|
||||
`${API_URL}/user_role/delete/${selectedPosition.id}/${enforce}`,
|
||||
{
|
||||
id: selectedPosition.id
|
||||
}
|
||||
);
|
||||
if (response?.status) {
|
||||
setAlert((prev) => ({ ...prev, show: false, message: '' }));
|
||||
handleDeleteDialog(false, null);
|
||||
toast.success('Success Delete Position');
|
||||
reload();
|
||||
const createActivity = {
|
||||
module: 'Manage Position',
|
||||
description: `Delete Position => ${selectedPosition.name}`,
|
||||
action: 'D'
|
||||
};
|
||||
|
||||
doSaveLogActivity(createActivity);
|
||||
} else {
|
||||
setAlert((prev) => ({ ...prev, show: true, message: response?.message }));
|
||||
}
|
||||
}, [selectedPosition, enforce]);
|
||||
|
||||
return (
|
||||
<Dialog open={showDeleteDialog} onOpenChange={(open) => handleDeleteDialog(open, null)}>
|
||||
<DialogContent className="container-fixed max-w-md flex flex-col p-5 overflow-hidden [&>button]:hidden">
|
||||
<DialogTitle></DialogTitle>
|
||||
<DialogHeader className="p-0 border-0 block">
|
||||
<Alert variant="warning">
|
||||
<h3 className="text-lg">Are you sure?</h3>
|
||||
<span className="text-sm">you will delete this data!</span>
|
||||
<div className="mt-2 flex items-center gap-x-2">
|
||||
<label className="form-label max-w-56">Hard Delete</label>
|
||||
<EnforceSwitch
|
||||
enforce={enforce}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
||||
setEnforce(e.target.checked);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</Alert>
|
||||
{alert.show && (
|
||||
<Alert variant="danger">
|
||||
<h3>{alert.message}</h3>
|
||||
</Alert>
|
||||
)}
|
||||
</DialogHeader>
|
||||
<DialogFooter className="flex justify-end items-center gap-4 mt-3">
|
||||
<Button variant={'outline'} onClick={() => handleDeleteDialog(false, null)}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button variant={'destructive'} onClick={() => doDeleteData()}>
|
||||
Delete
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export { DeleteDialog };
|
||||
226
src/pages/settings/user/manage-position/blocks/EditDialog.tsx
Normal file
226
src/pages/settings/user/manage-position/blocks/EditDialog.tsx
Normal file
@ -0,0 +1,226 @@
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
|
||||
import {
|
||||
Dialog,
|
||||
DialogBody,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle
|
||||
} from '@/components/ui/dialog';
|
||||
import { useManagePositionContext } from '../hooks';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { apiConfig } from '@/config/api.config';
|
||||
import { Alert, KeenIcon, useDataGrid } from '@/components';
|
||||
import { toast } from 'sonner';
|
||||
import { useCallApi } from '@/hooks';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue
|
||||
} from '@/components/ui/select';
|
||||
import { doSaveLogActivity } from '@/actions/GlobalActions';
|
||||
|
||||
const API_URL = apiConfig.service_dashboard;
|
||||
|
||||
interface MenuItem {
|
||||
id: string;
|
||||
name: string;
|
||||
children?: MenuItem[];
|
||||
}
|
||||
|
||||
const MenuItemComponent: React.FC<{
|
||||
menu: MenuItem;
|
||||
selectMenus: string[];
|
||||
handleCheckboxChange: (id: string) => void;
|
||||
}> = ({ menu, selectMenus, handleCheckboxChange }) => {
|
||||
const { id, name, children = [] } = menu;
|
||||
|
||||
return (
|
||||
<div className="mt-3">
|
||||
<div className="text-sm flex items-center gap-3">
|
||||
<Checkbox
|
||||
checked={selectMenus.includes(id)}
|
||||
id={`label-${id}`}
|
||||
onCheckedChange={() => handleCheckboxChange(id)}
|
||||
/>
|
||||
<label htmlFor={`label-${id}`}>{name}</label>
|
||||
</div>
|
||||
{children.length > 0 && (
|
||||
<div className="pl-5">
|
||||
{children.map((child) => (
|
||||
<MenuItemComponent
|
||||
key={child.id}
|
||||
menu={child}
|
||||
selectMenus={selectMenus}
|
||||
handleCheckboxChange={handleCheckboxChange}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const EditDialog = () => {
|
||||
const parentRef = useRef<any | null>(null);
|
||||
const { showEditDialog, handleEditDialog, menus, selectedPosition } = useManagePositionContext();
|
||||
const { reload } = useDataGrid();
|
||||
const { PutData } = useCallApi();
|
||||
const [alert, setAlert] = useState({
|
||||
show: false,
|
||||
message: ''
|
||||
});
|
||||
const [selectMenus, setSelectMenus] = useState<string[]>([]);
|
||||
const [formField, setFormField] = useState({
|
||||
name: '',
|
||||
status: ''
|
||||
});
|
||||
|
||||
/* actions */
|
||||
const handleCheckboxChange = useCallback((key: string) => {
|
||||
setSelectMenus((prev) =>
|
||||
prev.includes(key) ? prev.filter((item) => item !== key) : [...prev, key]
|
||||
);
|
||||
}, []);
|
||||
|
||||
const doEditPosition = useCallback(
|
||||
async (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
if (!selectedPosition) {
|
||||
toast.success('Please Select Position');
|
||||
return;
|
||||
}
|
||||
|
||||
const response = await PutData(`${API_URL}/user_role/update/${selectedPosition.id}`, {
|
||||
name: formField.name,
|
||||
roles: selectMenus,
|
||||
status: formField.status
|
||||
});
|
||||
|
||||
if (response?.status) {
|
||||
setAlert((prev) => ({ ...prev, show: false, message: '' }));
|
||||
handleEditDialog(false, null);
|
||||
toast.success('Success Update Position');
|
||||
reload();
|
||||
const createActivity = {
|
||||
module: 'Manage Position',
|
||||
description: `Edit Position => ${selectedPosition.name}`,
|
||||
action: 'U'
|
||||
};
|
||||
|
||||
doSaveLogActivity(createActivity);
|
||||
} else {
|
||||
setAlert((prev) => ({ ...prev, show: true, message: response?.message }));
|
||||
}
|
||||
},
|
||||
[formField, selectMenus, selectedPosition]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (selectedPosition) {
|
||||
setFormField((prev) => ({
|
||||
...prev,
|
||||
name: selectedPosition.name,
|
||||
status: selectedPosition.status
|
||||
}));
|
||||
|
||||
setSelectMenus(selectedPosition.roles);
|
||||
}
|
||||
}, [selectedPosition]);
|
||||
|
||||
return (
|
||||
<Dialog open={showEditDialog} onOpenChange={(open) => handleEditDialog(open, null)}>
|
||||
<DialogContent className="container-fixed max-w-[1024px] flex flex-col p-5 overflow-hidden [&>button]:hidden">
|
||||
<DialogHeader className="p-0 border-0">
|
||||
<DialogTitle></DialogTitle>
|
||||
<DialogDescription></DialogDescription>
|
||||
<div className="flex items-center justify-between flex-wrap grow">
|
||||
<div className="flex flex-col justify-center">
|
||||
<h1 className="text-xl font-semibold leading-none text-gray-900">Positions - Edit</h1>
|
||||
</div>
|
||||
<div
|
||||
className="cursor-pointer hover:opacity-100 opacity-50"
|
||||
onClick={() => handleEditDialog(false, null)}
|
||||
>
|
||||
<KeenIcon icon="cross" className="text-1.5xl" />
|
||||
</div>
|
||||
</div>
|
||||
</DialogHeader>
|
||||
<DialogBody className="scrollable-y px-0 pb-0" ref={parentRef}>
|
||||
<div className="flex flex-col px-0">
|
||||
{alert.show && (
|
||||
<Alert variant="danger" className="mb-3">
|
||||
<h3>{alert.message}</h3>
|
||||
</Alert>
|
||||
)}
|
||||
<form action="" onSubmit={doEditPosition}>
|
||||
<div className="card-body grid gap-5 p-0">
|
||||
<div className="w-full">
|
||||
<div className="flex items-baseline flex-wrap lg:flex-nowrap gap-2.5">
|
||||
<label className="form-label flex items-center gap-1 max-w-56">Name</label>
|
||||
<Input
|
||||
className="input"
|
||||
type="text"
|
||||
value={formField.name}
|
||||
onChange={({ target }) =>
|
||||
setFormField((prev) => ({ ...prev, name: target.value }))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="w-full">
|
||||
<div className="flex items-center flex-wrap gap-2.5">
|
||||
<label className="form-label max-w-56">Status</label>
|
||||
|
||||
<div className="grow">
|
||||
<Select
|
||||
value={formField.status}
|
||||
onValueChange={(status) => setFormField((prev) => ({ ...prev, status }))}
|
||||
>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="Y">Active</SelectItem>
|
||||
<SelectItem value="N">Non Active</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid md:grid-cols-3 w-full gap-5">
|
||||
{menus.map((menu) => (
|
||||
<div className="card" key={menu.id}>
|
||||
<div className="card-body p-5 pt-2">
|
||||
<MenuItemComponent
|
||||
menu={menu}
|
||||
selectMenus={selectMenus}
|
||||
handleCheckboxChange={handleCheckboxChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<hr />
|
||||
<div className="flex justify-end">
|
||||
<Button className="btn btn-primary" type="submit">
|
||||
Save Changes
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</DialogBody>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
export { EditDialog };
|
||||
@ -0,0 +1,43 @@
|
||||
import { DefaultTooltip, KeenIcon, useDataGrid } from '@/components';
|
||||
import { useManagePositionContext } from '../hooks';
|
||||
import { Button } from '@/components/ui/button';
|
||||
|
||||
const ListToolBar = () => {
|
||||
const { table, reload } = useDataGrid();
|
||||
const { handleAddDialog } = useManagePositionContext();
|
||||
|
||||
return (
|
||||
<div className="card-header flex-wrap gap-2 border-b-0 px-5">
|
||||
<div className="flex flex-wrap gap-2 lg:gap-5 w-full">
|
||||
<div className="flex justify-between w-full items-center">
|
||||
<label className="input input-sm w-1/6">
|
||||
<KeenIcon icon="magnifier" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Search roles"
|
||||
value={(table.getColumn('name')?.getFilterValue() as string) ?? ''}
|
||||
onChange={(event) => table.getColumn('name')?.setFilterValue(event.target.value)}
|
||||
/>
|
||||
</label>
|
||||
|
||||
<div className="flex gap-3 items-center">
|
||||
<Button
|
||||
variant="outline"
|
||||
className="h-7.5 text-[0.8rem]"
|
||||
onClick={() => handleAddDialog(true)}
|
||||
>
|
||||
Add Data
|
||||
</Button>
|
||||
<DefaultTooltip title={'Refresh'} placement={'top'}>
|
||||
<Button variant="outline" className="h-7.5" onClick={() => reload()}>
|
||||
<KeenIcon icon="arrows-circle" />
|
||||
</Button>
|
||||
</DefaultTooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export { ListToolBar };
|
||||
2
src/pages/settings/user/manage-position/blocks/index.ts
Normal file
2
src/pages/settings/user/manage-position/blocks/index.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export * from './ListToolBar';
|
||||
export * from './EditDialog'
|
||||
Reference in New Issue
Block a user