updating cycle close request feature to get approval from national dashboard instead auto from system

This commit is contained in:
Alberto-Audrix committed 2026-09-09 14:18:39 +07:00
1 parent 3a868cf1db
commit e4dbfd0252
31 files changed
+1322 -182

No files matched your search

+32 -14
View File
@@ -1,13 +1,20 @@
import React, { useEffect, useState } from 'react';
import { useFarm } from '../context/FarmContext.tsx';
import { formatDateId, formatDateRange, resolveCycleStatus } from '../utils/format.ts';
import {
formatDateId,
formatDateRange,
resolveCycleBoundDate,
resolveCycleStatus,
cycleLastDayIndex,
} from '../utils/format.ts';
import type { Cycle } from '../types/api.ts';
type Phase = { name: string; startDay: number; endDay: number; color: string };
function phasesFor(totalDays: number): Phase[] {
const starterEnd = Math.min(10, totalDays);
const growerEnd = Math.min(24, totalDays);
const safeDays = Math.max(totalDays, 1);
const starterEnd = Math.min(10, safeDays);
const growerEnd = Math.min(24, safeDays);
const phases: Phase[] = [
{ name: 'Starter', startDay: 1, endDay: starterEnd, color: 'bg-red-400' },
];
@@ -19,11 +26,11 @@ function phasesFor(totalDays: number): Phase[] {
color: 'bg-orange-400',
});
}
if (totalDays > growerEnd) {
if (safeDays > growerEnd) {
phases.push({
name: 'Finisher',
startDay: growerEnd + 1,
endDay: totalDays,
endDay: safeDays,
color: 'bg-yellow-500',
});
}
@@ -32,6 +39,12 @@ function phasesFor(totalDays: number): Phase[] {
const statusConfig = {
active: { label: 'Active', bg: 'bg-red-100', text: 'text-red-800', icon: 'fa-running' },
pending_close: {
label: 'Menunggu GM',
bg: 'bg-amber-100',
text: 'text-amber-800',
icon: 'fa-hourglass-half',
},
closed: {
label: 'Completed',
bg: 'bg-green-100',
@@ -41,10 +54,13 @@ const statusConfig = {
};
const SingleCycleView: React.FC<{ cycle: Cycle }> = ({ cycle }) => {
const phases = phasesFor(cycle.total_days);
const currentDay = Math.min(Math.max(cycle.current_day, 0), cycle.total_days);
const boundDate = resolveCycleBoundDate(cycle);
const displayTotalDays = Math.max(cycle.total_days || 1, cycleLastDayIndex(cycle) + 1);
const phases = phasesFor(displayTotalDays);
const currentDay = Math.min(Math.max(cycle.current_day, 0), displayTotalDays);
const cycleStatus = resolveCycleStatus(cycle);
const progress = cycle.total_days > 0 ? (currentDay / cycle.total_days) * 100 : 0;
const progress = displayTotalDays > 0 ? (currentDay / displayTotalDays) * 100 : 0;
const showMarker = cycleStatus === 'active' || cycleStatus === 'pending_close';
return (
<div className="pt-4">
@@ -54,14 +70,16 @@ const SingleCycleView: React.FC<{ cycle: Cycle }> = ({ cycle }) => {
<span className="font-semibold">{formatDateRange(cycle.start_date, cycle.end_date)}</span>
</p>
<div className="text-sm sm:text-right">
<p className="font-semibold text-gray-700">Estimasi Panen</p>
<p className="text-red-600 font-bold">{formatDateId(cycle.end_date)}</p>
<p className="font-semibold text-gray-700">
{cycle.end_date ? 'Estimasi Panen' : 'Batas data'}
</p>
<p className="text-red-600 font-bold">{formatDateId(cycle.end_date ?? boundDate)}</p>
</div>
</div>
<div className="relative pt-8">
<div className="relative h-8 bg-gray-200 rounded-lg flex items-center shadow-inner overflow-hidden">
{phases.map((phase) => {
const width = ((phase.endDay - phase.startDay + 1) / cycle.total_days) * 100;
const width = ((phase.endDay - phase.startDay + 1) / displayTotalDays) * 100;
return (
<div
key={phase.name}
@@ -74,7 +92,7 @@ const SingleCycleView: React.FC<{ cycle: Cycle }> = ({ cycle }) => {
);
})}
</div>
{cycleStatus === 'active' && (
{showMarker && (
<div
className="absolute top-0 transition-all duration-500 ease-out"
style={{ left: `calc(${progress}% - 2.5rem)` }}
@@ -101,9 +119,9 @@ const SingleCycleView: React.FC<{ cycle: Cycle }> = ({ cycle }) => {
</span>
</div>
<div className="flex flex-col items-end">
<span>Hari {cycle.total_days}</span>
<span>Hari {displayTotalDays}</span>
<span className="text-xs font-normal text-gray-400">
{formatDateId(cycle.end_date)}
{formatDateId(cycle.end_date ?? boundDate)}
</span>
</div>
</div>