mirror of
https://gitlab.com/mbugroup/lti-web-client.git
synced 2026-05-25 15:55:48 +00:00
feat: integrate DailyChecklistContent component to API
This commit is contained in:
@@ -7,7 +7,6 @@ import { Card, CardContent } from '@/figma-make/components/base/card';
|
|||||||
import { Button } from '@/figma-make/components/base/button';
|
import { Button } from '@/figma-make/components/base/button';
|
||||||
import { Label } from '@/figma-make/components/base/label';
|
import { Label } from '@/figma-make/components/base/label';
|
||||||
import { Input } from '@/figma-make/components/base/input';
|
import { Input } from '@/figma-make/components/base/input';
|
||||||
import { Textarea } from '@/figma-make/components/base/textarea';
|
|
||||||
import { Badge } from '@/figma-make/components/base/badge';
|
import { Badge } from '@/figma-make/components/base/badge';
|
||||||
import {
|
import {
|
||||||
Select,
|
Select,
|
||||||
@@ -26,7 +25,20 @@ import {
|
|||||||
} from '@/figma-make/components/base/dialog';
|
} from '@/figma-make/components/base/dialog';
|
||||||
import { DatePicker } from '@/figma-make/components/base/date-picker';
|
import { DatePicker } from '@/figma-make/components/base/date-picker';
|
||||||
import { toast } from 'sonner';
|
import { toast } from 'sonner';
|
||||||
import { supabase, isSupabaseConfigured } from '@/figma-make/lib/supabase';
|
import { useSelect } from '@/components/input/SelectInput';
|
||||||
|
import { KandangApi } from '@/services/api/master-data';
|
||||||
|
import { DailyChecklistApi } from '@/services/api/daily-checklist/daily-checklist';
|
||||||
|
import { isResponseError, isResponseSuccess } from '@/lib/api-helper';
|
||||||
|
import useSWR from 'swr';
|
||||||
|
import { BaseApiResponse } from '@/types/api/api-general';
|
||||||
|
import { AxiosError } from 'axios';
|
||||||
|
import { httpClientFetcher, SWRHttpKey } from '@/services/http/client';
|
||||||
|
import { PhaseApi } from '@/services/api/daily-checklist/phase';
|
||||||
|
import { EmployeeApi } from '@/services/api/daily-checklist/employee';
|
||||||
|
import { Employee } from '@/types/api/daily-checklist/employee';
|
||||||
|
import { PhaseActivityApi } from '@/services/api/daily-checklist/phase-activity';
|
||||||
|
import { PhaseActivity } from '@/types/api/daily-checklist/phase-activity';
|
||||||
|
import DebouncedTextArea from '@/components/input/DebouncedTextArea';
|
||||||
|
|
||||||
// Static categories
|
// Static categories
|
||||||
const CATEGORIES = [
|
const CATEGORIES = [
|
||||||
@@ -38,59 +50,68 @@ const CATEGORIES = [
|
|||||||
|
|
||||||
const TIME_TYPE_ORDER = ['umum', 'pagi', 'siang', 'sore', 'malam'];
|
const TIME_TYPE_ORDER = ['umum', 'pagi', 'siang', 'sore', 'malam'];
|
||||||
const TIME_TYPE_LABELS: { [key: string]: string } = {
|
const TIME_TYPE_LABELS: { [key: string]: string } = {
|
||||||
umum: 'Umum',
|
Umum: 'Umum',
|
||||||
pagi: 'Pagi',
|
Pagi: 'Pagi',
|
||||||
siang: 'Siang',
|
Siang: 'Siang',
|
||||||
sore: 'Sore',
|
Sore: 'Sore',
|
||||||
malam: 'Malam',
|
Malam: 'Malam',
|
||||||
};
|
};
|
||||||
|
|
||||||
interface Kandang {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Phase {
|
interface Phase {
|
||||||
id: string;
|
id: string;
|
||||||
name: 'string';
|
name: 'string';
|
||||||
category: string;
|
category: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Activity {
|
|
||||||
id: string;
|
|
||||||
phase_id: string;
|
|
||||||
name: string;
|
|
||||||
description?: string;
|
|
||||||
time_type: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Employee {
|
|
||||||
id: string;
|
|
||||||
name: string;
|
|
||||||
kandang_id: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface TaskAssignment {
|
|
||||||
task_id: string;
|
|
||||||
employee_id: string;
|
|
||||||
checked: boolean;
|
|
||||||
note: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function DailyChecklistContent() {
|
export function DailyChecklistContent() {
|
||||||
|
const [kandangId, setKandangId] = useState('');
|
||||||
|
|
||||||
|
const { options: kandangOptions, isLoadingOptions: isLoadingKandangs } =
|
||||||
|
useSelect(KandangApi.basePath, 'id', 'name', 'search', {
|
||||||
|
page: '1',
|
||||||
|
limit: '100',
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: phases,
|
||||||
|
isLoading: isLoadingPhases,
|
||||||
|
mutate: refreshPhases,
|
||||||
|
} = useSWR<
|
||||||
|
BaseApiResponse<Phase[] | undefined>,
|
||||||
|
AxiosError<BaseApiResponse>,
|
||||||
|
SWRHttpKey
|
||||||
|
>(`${PhaseApi.basePath}?page=1&limit=100`, httpClientFetcher, {
|
||||||
|
keepPreviousData: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: employeesRes,
|
||||||
|
isLoading: isLoadingEmployees,
|
||||||
|
mutate: refreshEmployees,
|
||||||
|
} = useSWR(
|
||||||
|
`${EmployeeApi.basePath}?page=1&limit=500&kandang_id=${kandangId}&is_active=true`,
|
||||||
|
EmployeeApi.getAllFetcher,
|
||||||
|
{
|
||||||
|
keepPreviousData: true,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
const allPhases = isResponseSuccess(phases) ? phases.data || [] : [];
|
||||||
|
const employees = isResponseSuccess(employeesRes)
|
||||||
|
? employeesRes.data || []
|
||||||
|
: [];
|
||||||
|
|
||||||
const [date, setDate] = useState(() => {
|
const [date, setDate] = useState(() => {
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
return today.toISOString().split('T')[0];
|
return today.toISOString().split('T')[0];
|
||||||
});
|
});
|
||||||
const [kandangId, setKandangId] = useState('');
|
|
||||||
const [selectedCategory, setSelectedCategory] = useState('');
|
const [selectedCategory, setSelectedCategory] = useState('');
|
||||||
const [selectedPhaseIds, setSelectedPhaseIds] = useState<string[]>([]);
|
const [selectedPhaseIds, setSelectedPhaseIds] = useState<string[]>([]);
|
||||||
const [checklistName, setChecklistName] = useState('');
|
|
||||||
|
|
||||||
const [kandangList, setKandangList] = useState<Kandang[]>([]);
|
const [selectedEmployees, setSelectedEmployees] = useState<
|
||||||
const [allPhases, setAllPhases] = useState<Phase[]>([]);
|
{ id: number; name: string }[]
|
||||||
const [employees, setEmployees] = useState<Employee[]>([]);
|
>([]);
|
||||||
const [selectedEmployees, setSelectedEmployees] = useState<Employee[]>([]);
|
|
||||||
|
|
||||||
const [dailyChecklistId, setDailyChecklistId] = useState<string | null>(null);
|
const [dailyChecklistId, setDailyChecklistId] = useState<string | null>(null);
|
||||||
const [checklistStatus, setChecklistStatus] = useState<string>('DRAFT');
|
const [checklistStatus, setChecklistStatus] = useState<string>('DRAFT');
|
||||||
@@ -98,7 +119,7 @@ export function DailyChecklistContent() {
|
|||||||
|
|
||||||
// Activities grouped by phase
|
// Activities grouped by phase
|
||||||
const [activitiesByPhase, setActivitiesByPhase] = useState<{
|
const [activitiesByPhase, setActivitiesByPhase] = useState<{
|
||||||
[phaseId: string]: Activity[];
|
[phaseId: string]: PhaseActivity[];
|
||||||
}>({});
|
}>({});
|
||||||
|
|
||||||
// Task IDs mapped by phase_activity_id for quick lookup
|
// Task IDs mapped by phase_activity_id for quick lookup
|
||||||
@@ -116,7 +137,7 @@ export function DailyChecklistContent() {
|
|||||||
const [showAbkModal, setShowAbkModal] = useState(false);
|
const [showAbkModal, setShowAbkModal] = useState(false);
|
||||||
const [showPhaseModal, setShowPhaseModal] = useState(false);
|
const [showPhaseModal, setShowPhaseModal] = useState(false);
|
||||||
const [tempSelectedEmployees, setTempSelectedEmployees] = useState<
|
const [tempSelectedEmployees, setTempSelectedEmployees] = useState<
|
||||||
Employee[]
|
{ id: number; name: string }[]
|
||||||
>([]);
|
>([]);
|
||||||
const [tempSelectedPhaseIds, setTempSelectedPhaseIds] = useState<string[]>(
|
const [tempSelectedPhaseIds, setTempSelectedPhaseIds] = useState<string[]>(
|
||||||
[]
|
[]
|
||||||
@@ -126,7 +147,6 @@ export function DailyChecklistContent() {
|
|||||||
|
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [initialLoading, setInitialLoading] = useState(true);
|
const [initialLoading, setInitialLoading] = useState(true);
|
||||||
const [datePickerOpen, setDatePickerOpen] = useState(false);
|
|
||||||
|
|
||||||
// Format date for display
|
// Format date for display
|
||||||
const formatDateForDisplay = (dateStr: string) => {
|
const formatDateForDisplay = (dateStr: string) => {
|
||||||
@@ -143,23 +163,13 @@ export function DailyChecklistContent() {
|
|||||||
|
|
||||||
// Fetch master data on mount
|
// Fetch master data on mount
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!isSupabaseConfigured()) {
|
|
||||||
console.warn(
|
|
||||||
'Supabase not configured. Please add environment variables.'
|
|
||||||
);
|
|
||||||
setInitialLoading(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchKandang();
|
|
||||||
fetchAllPhases();
|
|
||||||
setInitialLoading(false);
|
setInitialLoading(false);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Check for existing checklist when unique key changes
|
// Check for existing checklist when unique key changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const checkAndLoadChecklist = async () => {
|
const checkAndLoadChecklist = async () => {
|
||||||
if (!date || !kandangId || !selectedCategory || !isSupabaseConfigured()) {
|
if (!date || !kandangId || !selectedCategory) {
|
||||||
setDailyChecklistId(null);
|
setDailyChecklistId(null);
|
||||||
setChecklistStatus('DRAFT');
|
setChecklistStatus('DRAFT');
|
||||||
setIsEditMode(false);
|
setIsEditMode(false);
|
||||||
@@ -171,55 +181,47 @@ export function DailyChecklistContent() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// UPSERT to get or create checklist (UNIQUE KEY: date, kandang_id, category)
|
const checklist = await DailyChecklistApi.create({
|
||||||
const { data: checklist, error } = await supabase
|
date,
|
||||||
.from('daily_checklists')
|
kandang_id: Number(kandangId),
|
||||||
.upsert(
|
category: selectedCategory,
|
||||||
{
|
status: 'DRAFT',
|
||||||
date,
|
});
|
||||||
kandang_id: kandangId,
|
|
||||||
category: selectedCategory,
|
|
||||||
status: 'DRAFT',
|
|
||||||
updated_at: new Date().toISOString(),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
onConflict: 'date,kandang_id,category',
|
|
||||||
ignoreDuplicates: false,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.select()
|
|
||||||
.single();
|
|
||||||
|
|
||||||
if (error) {
|
if (isResponseError(checklist)) {
|
||||||
console.error('Error upserting checklist:', error);
|
console.error('Error upserting checklist:', checklist.message);
|
||||||
toast.error('Gagal memuat checklist');
|
toast.error('Gagal memuat checklist');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setDailyChecklistId(checklist.id);
|
setDailyChecklistId(String(checklist?.data?.id));
|
||||||
setChecklistStatus(checklist.status);
|
setChecklistStatus(String(checklist?.data?.status));
|
||||||
|
|
||||||
// Load existing phases for this checklist
|
const existingPhases = await DailyChecklistApi.getOneDailyChecklist(
|
||||||
const { data: existingPhases, error: phaseError } = await supabase
|
String(checklist?.data.id)
|
||||||
.from('daily_checklist_phases')
|
);
|
||||||
.select('phase_id')
|
|
||||||
.eq('checklist_id', checklist.id); // ✅ Uses checklist_id
|
|
||||||
|
|
||||||
if (phaseError) {
|
if (isResponseError(existingPhases)) {
|
||||||
console.error('Error loading phases:', phaseError);
|
console.error('Error loading phases:', existingPhases.message);
|
||||||
} else if (existingPhases && existingPhases.length > 0) {
|
} else if (
|
||||||
|
existingPhases &&
|
||||||
|
existingPhases.data &&
|
||||||
|
existingPhases.data.phases.length > 0
|
||||||
|
) {
|
||||||
// Existing checklist - EDIT MODE
|
// Existing checklist - EDIT MODE
|
||||||
setIsEditMode(true);
|
setIsEditMode(true);
|
||||||
const phaseIds = existingPhases.map((p) => p.phase_id);
|
const phaseIds = existingPhases.data.phases.map((p) =>
|
||||||
|
String(p.phase_id)
|
||||||
|
);
|
||||||
setSelectedPhaseIds(phaseIds);
|
setSelectedPhaseIds(phaseIds);
|
||||||
|
|
||||||
if (checklist.status === 'DRAFT') {
|
if (checklist?.data?.status === 'DRAFT') {
|
||||||
toast.info('Checklist ditemukan - Mode Edit (Draft)', {
|
toast.info('Checklist ditemukan - Mode Edit (Draft)', {
|
||||||
description:
|
description:
|
||||||
'Anda dapat menambah atau mengubah data checklist ini',
|
'Anda dapat menambah atau mengubah data checklist ini',
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
toast.warning(`Checklist sudah ${checklist.status}`, {
|
toast.warning(`Checklist sudah ${checklist?.data?.status}`, {
|
||||||
description: 'Checklist tidak dapat diedit',
|
description: 'Checklist tidak dapat diedit',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -239,32 +241,27 @@ export function DailyChecklistContent() {
|
|||||||
// Load activities and tasks when phases change
|
// Load activities and tasks when phases change
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const loadActivitiesAndTasks = async () => {
|
const loadActivitiesAndTasks = async () => {
|
||||||
if (
|
if (!dailyChecklistId || selectedPhaseIds.length === 0) {
|
||||||
!dailyChecklistId ||
|
|
||||||
selectedPhaseIds.length === 0 ||
|
|
||||||
!isSupabaseConfigured()
|
|
||||||
) {
|
|
||||||
setActivitiesByPhase({});
|
setActivitiesByPhase({});
|
||||||
setTaskIdsByPhaseActivityId({});
|
setTaskIdsByPhaseActivityId({});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Fetch activities for selected phases
|
const activitiesRes = await PhaseActivityApi.getAll({
|
||||||
const { data: activities, error: actError } = await supabase
|
phase_ids: selectedPhaseIds.join(','),
|
||||||
.from('phase_activities')
|
});
|
||||||
.select('id, phase_id, name, description, time_type')
|
|
||||||
.in('phase_id', selectedPhaseIds)
|
|
||||||
.order('id', { ascending: true }); // ✅ Urutan berdasarkan ID (yang paling awal diinput di atas)
|
|
||||||
|
|
||||||
if (actError) {
|
if (isResponseError(activitiesRes)) {
|
||||||
console.error('Error loading activities:', actError);
|
console.error('Error loading activities:', activitiesRes.message);
|
||||||
toast.error('Gagal memuat aktivitas');
|
toast.error('Gagal memuat aktivitas');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const activities = activitiesRes?.data || [];
|
||||||
|
|
||||||
// Group activities by phase
|
// Group activities by phase
|
||||||
const grouped: { [phaseId: string]: Activity[] } = {};
|
const grouped: { [phaseId: string]: PhaseActivity[] } = {};
|
||||||
(activities || []).forEach((act) => {
|
(activities || []).forEach((act) => {
|
||||||
if (!grouped[act.phase_id]) {
|
if (!grouped[act.phase_id]) {
|
||||||
grouped[act.phase_id] = [];
|
grouped[act.phase_id] = [];
|
||||||
@@ -283,28 +280,30 @@ export function DailyChecklistContent() {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
if (taskUpserts.length > 0) {
|
if (taskUpserts.length > 0) {
|
||||||
const { data: tasks, error: taskError } = await supabase
|
const existingDailyChecklist =
|
||||||
.from('daily_checklist_activity_tasks')
|
await DailyChecklistApi.getOneDailyChecklist(
|
||||||
.upsert(taskUpserts, {
|
String(dailyChecklistId)
|
||||||
onConflict: 'checklist_id,phase_activity_id',
|
);
|
||||||
ignoreDuplicates: false,
|
|
||||||
})
|
|
||||||
.select('id, phase_activity_id');
|
|
||||||
|
|
||||||
if (taskError) {
|
if (isResponseError(existingDailyChecklist)) {
|
||||||
console.error('Error upserting tasks:', taskError);
|
console.error(
|
||||||
|
'Error loading assignments:',
|
||||||
|
existingDailyChecklist.message
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build task ID lookup
|
// Build task ID lookup
|
||||||
const taskMap: { [phaseActivityId: string]: string } = {};
|
const taskMap: { [phaseActivityId: string]: string } = {};
|
||||||
(tasks || []).forEach((task) => {
|
(existingDailyChecklist?.data?.tasks || []).forEach((task) => {
|
||||||
taskMap[task.phase_activity_id] = task.id;
|
taskMap[String(task.phase_activity_id)] = String(task.id);
|
||||||
});
|
});
|
||||||
setTaskIdsByPhaseActivityId(taskMap);
|
setTaskIdsByPhaseActivityId(taskMap);
|
||||||
|
|
||||||
// Load existing assignments for these tasks
|
// Load existing assignments for these tasks
|
||||||
await loadAssignments(tasks.map((t) => t.id));
|
await loadAssignments(
|
||||||
|
existingDailyChecklist?.data?.tasks?.map((t) => String(t.id)) || []
|
||||||
|
);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading activities and tasks:', error);
|
console.error('Error loading activities and tasks:', error);
|
||||||
@@ -316,29 +315,28 @@ export function DailyChecklistContent() {
|
|||||||
|
|
||||||
// Load employees when kandang changes
|
// Load employees when kandang changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (kandangId && isSupabaseConfigured()) {
|
if (kandangId) {
|
||||||
fetchEmployees(kandangId);
|
|
||||||
// ✅ Clear selected employees ketika kandang berubah (reset ABK assignment)
|
// ✅ Clear selected employees ketika kandang berubah (reset ABK assignment)
|
||||||
setSelectedEmployees([]);
|
setSelectedEmployees([]);
|
||||||
setAssignments({});
|
setAssignments({});
|
||||||
} else {
|
} else {
|
||||||
setEmployees([]);
|
|
||||||
setSelectedEmployees([]);
|
setSelectedEmployees([]);
|
||||||
setAssignments({});
|
setAssignments({});
|
||||||
}
|
}
|
||||||
}, [kandangId]);
|
}, [kandangId]);
|
||||||
|
|
||||||
const loadAssignments = async (taskIds: string[]) => {
|
const loadAssignments = async (taskIds: string[]) => {
|
||||||
if (taskIds.length === 0 || !isSupabaseConfigured()) return;
|
if (taskIds.length === 0) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const { data, error } = await supabase
|
const existingDailyChecklist =
|
||||||
.from('daily_checklist_activity_task_assignments')
|
await DailyChecklistApi.getOneDailyChecklist(String(dailyChecklistId));
|
||||||
.select('task_id, employee_id, checked, note')
|
|
||||||
.in('task_id', taskIds);
|
|
||||||
|
|
||||||
if (error) {
|
if (isResponseError(existingDailyChecklist)) {
|
||||||
console.error('Error loading assignments:', error);
|
console.error(
|
||||||
|
'Error loading assignments:',
|
||||||
|
existingDailyChecklist.message
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,30 +347,43 @@ export function DailyChecklistContent() {
|
|||||||
};
|
};
|
||||||
} = {};
|
} = {};
|
||||||
|
|
||||||
(data || []).forEach((assignment) => {
|
(existingDailyChecklist?.data.tasks || []).forEach(
|
||||||
if (!assignmentMap[assignment.task_id]) {
|
(dailyChecklistTask) => {
|
||||||
assignmentMap[assignment.task_id] = {};
|
if (!assignmentMap[dailyChecklistTask.id]) {
|
||||||
|
assignmentMap[dailyChecklistTask.id] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
dailyChecklistTask.assignments.forEach((assignment) => {
|
||||||
|
if (!assignmentMap[dailyChecklistTask.id]) {
|
||||||
|
assignmentMap[dailyChecklistTask.id] = {};
|
||||||
|
}
|
||||||
|
assignmentMap[dailyChecklistTask.id][assignment.employee.id] = {
|
||||||
|
checked: assignment.checked,
|
||||||
|
note: assignment.note || '',
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
assignmentMap[assignment.task_id][assignment.employee_id] = {
|
);
|
||||||
checked: assignment.checked,
|
|
||||||
note: assignment.note || '',
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
setAssignments(assignmentMap);
|
setAssignments(assignmentMap);
|
||||||
|
|
||||||
// Load employees from assignments
|
// Load employees from assignments
|
||||||
const employeeIds = Array.from(
|
const employeeIds = Array.from(
|
||||||
new Set((data || []).map((a) => a.employee_id))
|
new Set(
|
||||||
|
(existingDailyChecklist?.data.assigned_employees || []).map(
|
||||||
|
(a) => a.id
|
||||||
|
)
|
||||||
|
)
|
||||||
);
|
);
|
||||||
if (employeeIds.length > 0) {
|
|
||||||
const { data: empData, error: empError } = await supabase
|
|
||||||
.from('employees')
|
|
||||||
.select('id, name, kandang_id')
|
|
||||||
.in('id', employeeIds);
|
|
||||||
|
|
||||||
if (!empError && empData) {
|
if (employeeIds.length > 0) {
|
||||||
setSelectedEmployees(empData);
|
const existingDailyChecklist =
|
||||||
|
await DailyChecklistApi.getOneDailyChecklist(
|
||||||
|
String(dailyChecklistId)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isResponseSuccess(existingDailyChecklist)) {
|
||||||
|
setSelectedEmployees(existingDailyChecklist.data.assigned_employees);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -380,68 +391,6 @@ export function DailyChecklistContent() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const fetchKandang = async () => {
|
|
||||||
if (!isSupabaseConfigured()) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const { data, error } = await supabase
|
|
||||||
.from('kandang')
|
|
||||||
.select('id, name')
|
|
||||||
.order('name', { ascending: true });
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
console.error('Error fetching kandang:', error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setKandangList(data || []);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching kandang:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetchAllPhases = async () => {
|
|
||||||
if (!isSupabaseConfigured()) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const { data, error } = await supabase
|
|
||||||
.from('phases')
|
|
||||||
.select('id, name, category')
|
|
||||||
.order('id', { ascending: true }); // ✅ Urutan berdasarkan ID (yang paling awal diinput di atas)
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
console.error('Error fetching phases:', error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setAllPhases(data || []);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching phases:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const fetchEmployees = async (kandangId: string) => {
|
|
||||||
if (!isSupabaseConfigured()) return;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const { data, error } = await supabase
|
|
||||||
.from('employees')
|
|
||||||
.select('id, name, kandang_id')
|
|
||||||
.eq('kandang_id', kandangId)
|
|
||||||
.eq('is_active', true)
|
|
||||||
.order('name', { ascending: true });
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
console.error('Error fetching employees:', error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setEmployees(data || []);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching employees:', error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Phase selection modal
|
// Phase selection modal
|
||||||
const handleAddPhase = () => {
|
const handleAddPhase = () => {
|
||||||
if (!selectedCategory) {
|
if (!selectedCategory) {
|
||||||
@@ -464,31 +413,25 @@ export function DailyChecklistContent() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const applyPhaseSelection = async () => {
|
const applyPhaseSelection = async () => {
|
||||||
if (!dailyChecklistId || !isSupabaseConfigured()) {
|
if (!dailyChecklistId) {
|
||||||
toast.error('Checklist belum tersedia');
|
toast.error('Checklist belum tersedia');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Delete existing phase links
|
|
||||||
await supabase
|
|
||||||
.from('daily_checklist_phases')
|
|
||||||
.delete()
|
|
||||||
.eq('checklist_id', dailyChecklistId);
|
|
||||||
|
|
||||||
// Insert new phase links
|
// Insert new phase links
|
||||||
if (tempSelectedPhaseIds.length > 0) {
|
if (tempSelectedPhaseIds.length > 0) {
|
||||||
const phaseLinks = tempSelectedPhaseIds.map((phaseId) => ({
|
const setDailyChecklistPhaseRes =
|
||||||
checklist_id: dailyChecklistId,
|
await DailyChecklistApi.setDailyChecklistPhase(
|
||||||
phase_id: phaseId,
|
dailyChecklistId,
|
||||||
}));
|
tempSelectedPhaseIds
|
||||||
|
);
|
||||||
|
|
||||||
const { error } = await supabase
|
if (isResponseError(setDailyChecklistPhaseRes)) {
|
||||||
.from('daily_checklist_phases')
|
console.error(
|
||||||
.insert(phaseLinks);
|
'Error saving phases:',
|
||||||
|
setDailyChecklistPhaseRes.message
|
||||||
if (error) {
|
);
|
||||||
console.error('Error saving phases:', error);
|
|
||||||
toast.error('Gagal menyimpan fase');
|
toast.error('Gagal menyimpan fase');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -545,18 +488,23 @@ export function DailyChecklistContent() {
|
|||||||
(emp) => !tempSelectedEmployees.find((temp) => temp.id === emp.id)
|
(emp) => !tempSelectedEmployees.find((temp) => temp.id === emp.id)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (removedEmployees.length > 0 && isSupabaseConfigured()) {
|
if (removedEmployees.length > 0) {
|
||||||
const taskIds = Object.values(taskIdsByPhaseActivityId);
|
removedEmployees.forEach(async (removedEmp) => {
|
||||||
if (taskIds.length > 0) {
|
const removeEmployeeAssignmentRes =
|
||||||
await supabase
|
await DailyChecklistApi.removeEmployeeAssignment(
|
||||||
.from('daily_checklist_activity_task_assignments')
|
dailyChecklistId,
|
||||||
.delete()
|
String(removedEmp.id)
|
||||||
.in('task_id', taskIds)
|
|
||||||
.in(
|
|
||||||
'employee_id',
|
|
||||||
removedEmployees.map((e) => e.id)
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
if (isResponseError(removeEmployeeAssignmentRes)) {
|
||||||
|
console.error(
|
||||||
|
'Error removing employee assignment:',
|
||||||
|
removeEmployeeAssignmentRes.message
|
||||||
|
);
|
||||||
|
toast.error('Gagal menghapus tugas');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Remove from state
|
// Remove from state
|
||||||
const newAssignments = { ...assignments };
|
const newAssignments = { ...assignments };
|
||||||
@@ -573,7 +521,7 @@ export function DailyChecklistContent() {
|
|||||||
(temp) => !selectedEmployees.find((emp) => emp.id === temp.id)
|
(temp) => !selectedEmployees.find((emp) => emp.id === temp.id)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (addedEmployees.length > 0 && isSupabaseConfigured()) {
|
if (addedEmployees.length > 0) {
|
||||||
const taskIds = Object.values(taskIdsByPhaseActivityId);
|
const taskIds = Object.values(taskIdsByPhaseActivityId);
|
||||||
const newAssignments: {
|
const newAssignments: {
|
||||||
task_id: string;
|
task_id: string;
|
||||||
@@ -586,20 +534,23 @@ export function DailyChecklistContent() {
|
|||||||
addedEmployees.forEach((emp) => {
|
addedEmployees.forEach((emp) => {
|
||||||
newAssignments.push({
|
newAssignments.push({
|
||||||
task_id: taskId,
|
task_id: taskId,
|
||||||
employee_id: emp.id,
|
employee_id: String(emp.id),
|
||||||
checked: false,
|
checked: false,
|
||||||
note: null,
|
note: null,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
if (newAssignments.length > 0) {
|
const assignEmployeeRes =
|
||||||
await supabase
|
await DailyChecklistApi.setDailyChecklistEmployees(
|
||||||
.from('daily_checklist_activity_task_assignments')
|
dailyChecklistId,
|
||||||
.upsert(newAssignments, {
|
addedEmployees.map((emp) => String(emp.id))
|
||||||
onConflict: 'task_id,employee_id',
|
);
|
||||||
ignoreDuplicates: false,
|
|
||||||
});
|
if (isResponseError(assignEmployeeRes)) {
|
||||||
|
console.error('Error assigning employees:', assignEmployeeRes.message);
|
||||||
|
toast.error('Gagal mengassign ABK: ' + assignEmployeeRes.message);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -610,16 +561,15 @@ export function DailyChecklistContent() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleRemoveAbk = async (employeeId: string) => {
|
const handleRemoveAbk = async (employeeId: string) => {
|
||||||
if (!isSupabaseConfigured()) return;
|
const deleteEmployeeRes = await DailyChecklistApi.removeEmployeeAssignment(
|
||||||
|
String(dailyChecklistId),
|
||||||
|
String(employeeId)
|
||||||
|
);
|
||||||
|
|
||||||
// Delete assignments for this employee
|
if (isResponseError(deleteEmployeeRes)) {
|
||||||
const taskIds = Object.values(taskIdsByPhaseActivityId);
|
console.error('Error deleting employee:', deleteEmployeeRes.message);
|
||||||
if (taskIds.length > 0) {
|
toast.error('Gagal menghapus ABK: ' + deleteEmployeeRes.message);
|
||||||
await supabase
|
return;
|
||||||
.from('daily_checklist_activity_task_assignments')
|
|
||||||
.delete()
|
|
||||||
.in('task_id', taskIds)
|
|
||||||
.eq('employee_id', employeeId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove from state
|
// Remove from state
|
||||||
@@ -629,7 +579,9 @@ export function DailyChecklistContent() {
|
|||||||
});
|
});
|
||||||
setAssignments(newAssignments);
|
setAssignments(newAssignments);
|
||||||
|
|
||||||
setSelectedEmployees(selectedEmployees.filter((e) => e.id !== employeeId));
|
setSelectedEmployees(
|
||||||
|
selectedEmployees.filter((e) => String(e.id) !== employeeId)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCheckboxChange = async (
|
const handleCheckboxChange = async (
|
||||||
@@ -645,7 +597,6 @@ export function DailyChecklistContent() {
|
|||||||
checked,
|
checked,
|
||||||
taskId,
|
taskId,
|
||||||
hasTaskId: !!taskId,
|
hasTaskId: !!taskId,
|
||||||
isSupabaseConfigured: isSupabaseConfigured(),
|
|
||||||
checklistStatus,
|
checklistStatus,
|
||||||
isEditable,
|
isEditable,
|
||||||
});
|
});
|
||||||
@@ -657,12 +608,6 @@ export function DailyChecklistContent() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isSupabaseConfigured()) {
|
|
||||||
console.error('[CHECKBOX] Supabase not configured');
|
|
||||||
toast.error('Database tidak terkonfigurasi');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isEditable) {
|
if (!isEditable) {
|
||||||
console.warn(
|
console.warn(
|
||||||
'[CHECKBOX] Checklist is not editable, status:',
|
'[CHECKBOX] Checklist is not editable, status:',
|
||||||
@@ -692,24 +637,23 @@ export function DailyChecklistContent() {
|
|||||||
|
|
||||||
// Update database
|
// Update database
|
||||||
const payload = {
|
const payload = {
|
||||||
task_id: taskId,
|
task_id: Number(taskId),
|
||||||
employee_id: employeeId,
|
employee_id: Number(employeeId),
|
||||||
checked,
|
checked,
|
||||||
note: assignments[taskId]?.[employeeId]?.note || null,
|
note: assignments[taskId]?.[employeeId]?.note || null,
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('[CHECKBOX] Saving to database:', payload);
|
console.log('[CHECKBOX] Saving to database:', payload);
|
||||||
|
|
||||||
const { error } = await supabase
|
const checkOrUncheckAssignmentRes =
|
||||||
.from('daily_checklist_activity_task_assignments')
|
await DailyChecklistApi.checkOrUncheckAssignment(payload);
|
||||||
.upsert(payload, {
|
|
||||||
onConflict: 'task_id,employee_id',
|
|
||||||
ignoreDuplicates: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (error) {
|
if (isResponseError(checkOrUncheckAssignmentRes)) {
|
||||||
console.error('[CHECKBOX] Database error:', error);
|
console.error(
|
||||||
toast.error('Gagal menyimpan: ' + error.message);
|
'[CHECKBOX] Database error:',
|
||||||
|
checkOrUncheckAssignmentRes.message
|
||||||
|
);
|
||||||
|
toast.error('Gagal menyimpan: ' + checkOrUncheckAssignmentRes.message);
|
||||||
|
|
||||||
// Revert state on error
|
// Revert state on error
|
||||||
setAssignments((prev) => ({
|
setAssignments((prev) => ({
|
||||||
@@ -734,26 +678,25 @@ export function DailyChecklistContent() {
|
|||||||
note: string
|
note: string
|
||||||
) => {
|
) => {
|
||||||
const taskId = taskIdsByPhaseActivityId[activityId];
|
const taskId = taskIdsByPhaseActivityId[activityId];
|
||||||
if (!taskId || !isSupabaseConfigured()) return;
|
if (!taskId) return;
|
||||||
|
|
||||||
// Update database
|
// Update database
|
||||||
const { error } = await supabase
|
const payload = {
|
||||||
.from('daily_checklist_activity_task_assignments')
|
task_id: Number(taskId),
|
||||||
.upsert(
|
employee_id: Number(employeeId),
|
||||||
{
|
checked: assignments[taskId]?.[employeeId]?.checked || false,
|
||||||
task_id: taskId,
|
note: note || null,
|
||||||
employee_id: employeeId,
|
};
|
||||||
checked: assignments[taskId]?.[employeeId]?.checked || false,
|
|
||||||
note: note || null,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
onConflict: 'task_id,employee_id',
|
|
||||||
ignoreDuplicates: false,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (error) {
|
const checkOrUncheckAssignmentRes =
|
||||||
console.error('Error updating note:', error);
|
await DailyChecklistApi.checkOrUncheckAssignment(payload);
|
||||||
|
|
||||||
|
if (isResponseError(checkOrUncheckAssignmentRes)) {
|
||||||
|
console.error(
|
||||||
|
'[CHECKBOX] Database error:',
|
||||||
|
checkOrUncheckAssignmentRes.message
|
||||||
|
);
|
||||||
|
toast.error('Gagal menyimpan: ' + checkOrUncheckAssignmentRes.message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -771,7 +714,7 @@ export function DailyChecklistContent() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
if (!dailyChecklistId || !isSupabaseConfigured()) return;
|
if (!dailyChecklistId) return;
|
||||||
|
|
||||||
if (selectedEmployees.length === 0) {
|
if (selectedEmployees.length === 0) {
|
||||||
toast.error('Pilih minimal 1 ABK');
|
toast.error('Pilih minimal 1 ABK');
|
||||||
@@ -786,17 +729,10 @@ export function DailyChecklistContent() {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Update status to SUBMITTED
|
const submitRes = await DailyChecklistApi.submit(dailyChecklistId);
|
||||||
const { error } = await supabase
|
|
||||||
.from('daily_checklists')
|
|
||||||
.update({
|
|
||||||
status: 'SUBMITTED',
|
|
||||||
updated_at: new Date().toISOString(),
|
|
||||||
})
|
|
||||||
.eq('id', dailyChecklistId);
|
|
||||||
|
|
||||||
if (error) {
|
if (isResponseError(submitRes)) {
|
||||||
console.error('Error submitting:', error);
|
console.error('Error submitting:', submitRes.message);
|
||||||
toast.error('Gagal submit checklist');
|
toast.error('Gagal submit checklist');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -841,13 +777,13 @@ export function DailyChecklistContent() {
|
|||||||
[phaseId: string]: {
|
[phaseId: string]: {
|
||||||
phase: Phase;
|
phase: Phase;
|
||||||
timeGroups: {
|
timeGroups: {
|
||||||
[timeType: string]: Activity[];
|
[timeType: string]: PhaseActivity[];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
} = {};
|
} = {};
|
||||||
|
|
||||||
const selectedPhasesData = allPhases.filter((p) =>
|
const selectedPhasesData = allPhases.filter((p) =>
|
||||||
selectedPhaseIds.includes(p.id)
|
selectedPhaseIds.includes(String(p.id))
|
||||||
);
|
);
|
||||||
|
|
||||||
selectedPhasesData.forEach((phase) => {
|
selectedPhasesData.forEach((phase) => {
|
||||||
@@ -900,7 +836,7 @@ export function DailyChecklistContent() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='min-h-screen bg-[#F9FAFB]'>
|
<div className='min-h-screen'>
|
||||||
<div className='p-6'>
|
<div className='p-6'>
|
||||||
{/* Page Title */}
|
{/* Page Title */}
|
||||||
<div className='mb-6'>
|
<div className='mb-6'>
|
||||||
@@ -967,9 +903,12 @@ export function DailyChecklistContent() {
|
|||||||
<SelectValue placeholder='Pilih kandang' />
|
<SelectValue placeholder='Pilih kandang' />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
{kandangList.map((kandang) => (
|
{kandangOptions.map((kandang) => (
|
||||||
<SelectItem key={kandang.id} value={kandang.id}>
|
<SelectItem
|
||||||
{kandang.name}
|
key={kandang.value}
|
||||||
|
value={String(kandang.value)}
|
||||||
|
>
|
||||||
|
{kandang.label}
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
))}
|
))}
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
@@ -1022,7 +961,7 @@ export function DailyChecklistContent() {
|
|||||||
{selectedPhaseIds.length > 0 ? (
|
{selectedPhaseIds.length > 0 ? (
|
||||||
<div className='flex flex-wrap gap-2'>
|
<div className='flex flex-wrap gap-2'>
|
||||||
{allPhases
|
{allPhases
|
||||||
.filter((p) => selectedPhaseIds.includes(p.id))
|
.filter((p) => selectedPhaseIds.includes(String(p.id)))
|
||||||
.map((phase) => (
|
.map((phase) => (
|
||||||
<Badge
|
<Badge
|
||||||
key={phase.id}
|
key={phase.id}
|
||||||
@@ -1069,7 +1008,7 @@ export function DailyChecklistContent() {
|
|||||||
{emp.name}
|
{emp.name}
|
||||||
{isEditable && (
|
{isEditable && (
|
||||||
<button
|
<button
|
||||||
onClick={() => handleRemoveAbk(emp.id)}
|
onClick={() => handleRemoveAbk(String(emp.id))}
|
||||||
className='ml-2 hover:text-gray-900'
|
className='ml-2 hover:text-gray-900'
|
||||||
>
|
>
|
||||||
<X className='w-3 h-3' />
|
<X className='w-3 h-3' />
|
||||||
@@ -1226,8 +1165,8 @@ export function DailyChecklistContent() {
|
|||||||
}
|
}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
handleCheckboxChange(
|
handleCheckboxChange(
|
||||||
activity.id,
|
String(activity.id),
|
||||||
emp.id,
|
String(emp.id),
|
||||||
e.target.checked
|
e.target.checked
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1237,7 +1176,11 @@ export function DailyChecklistContent() {
|
|||||||
</td>
|
</td>
|
||||||
))}
|
))}
|
||||||
<td className='py-3 px-4'>
|
<td className='py-3 px-4'>
|
||||||
<Textarea
|
<DebouncedTextArea
|
||||||
|
delay={500}
|
||||||
|
name='notes'
|
||||||
|
rows={1}
|
||||||
|
placeholder='Catatan (opsional)'
|
||||||
value={
|
value={
|
||||||
taskId && selectedEmployees.length > 0
|
taskId && selectedEmployees.length > 0
|
||||||
? assignments[taskId]?.[
|
? assignments[taskId]?.[
|
||||||
@@ -1248,16 +1191,13 @@ export function DailyChecklistContent() {
|
|||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
if (selectedEmployees.length > 0) {
|
if (selectedEmployees.length > 0) {
|
||||||
handleNoteChange(
|
handleNoteChange(
|
||||||
activity.id,
|
String(activity.id),
|
||||||
selectedEmployees[0].id,
|
String(selectedEmployees[0].id),
|
||||||
e.target.value
|
e.target.value
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
placeholder='Catatan (opsional)'
|
|
||||||
disabled={!isEditable}
|
disabled={!isEditable}
|
||||||
className='text-sm min-h-[36px] resize-none'
|
|
||||||
rows={1}
|
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -1401,7 +1341,9 @@ export function DailyChecklistContent() {
|
|||||||
{filteredPhases.length > 0 ? (
|
{filteredPhases.length > 0 ? (
|
||||||
<div className='space-y-1.5'>
|
<div className='space-y-1.5'>
|
||||||
{filteredPhases.map((phase) => {
|
{filteredPhases.map((phase) => {
|
||||||
const isChecked = tempSelectedPhaseIds.includes(phase.id);
|
const isChecked = tempSelectedPhaseIds.includes(
|
||||||
|
String(phase.id)
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<label
|
<label
|
||||||
@@ -1415,7 +1357,7 @@ export function DailyChecklistContent() {
|
|||||||
<input
|
<input
|
||||||
type='checkbox'
|
type='checkbox'
|
||||||
checked={isChecked}
|
checked={isChecked}
|
||||||
onChange={() => toggleTempPhase(phase.id)}
|
onChange={() => toggleTempPhase(String(phase.id))}
|
||||||
className='checkbox-clean mt-0.5'
|
className='checkbox-clean mt-0.5'
|
||||||
/>
|
/>
|
||||||
<div className='flex-1 min-w-0'>
|
<div className='flex-1 min-w-0'>
|
||||||
@@ -1507,9 +1449,22 @@ export function DailyChecklistContent() {
|
|||||||
const isChecked = tempSelectedEmployees.find(
|
const isChecked = tempSelectedEmployees.find(
|
||||||
(e) => e.id === emp.id
|
(e) => e.id === emp.id
|
||||||
);
|
);
|
||||||
const kandang = kandangList.find(
|
// const kandang = kandangOptions.find((k) => {
|
||||||
(k) => k.id === emp.kandang_id
|
// const formattedKandangIds = emp.kandangs.map((empKandang) =>
|
||||||
);
|
// String(empKandang.id)
|
||||||
|
// );
|
||||||
|
// return formattedKandangIds.includes(String(k.value));
|
||||||
|
// });
|
||||||
|
|
||||||
|
const kandang = emp.kandangs
|
||||||
|
.map((empKandang) => {
|
||||||
|
if (String(empKandang.id) === kandangId) {
|
||||||
|
return `<b>${empKandang.name}</b>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return empKandang.name;
|
||||||
|
})
|
||||||
|
.join(', ');
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<label
|
<label
|
||||||
@@ -1532,7 +1487,9 @@ export function DailyChecklistContent() {
|
|||||||
</p>
|
</p>
|
||||||
{kandang && (
|
{kandang && (
|
||||||
<p className='text-xs text-gray-500 mt-0.5'>
|
<p className='text-xs text-gray-500 mt-0.5'>
|
||||||
{kandang.name}
|
<span
|
||||||
|
dangerouslySetInnerHTML={{ __html: kandang }}
|
||||||
|
/>
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user