commit
32a36cceff
444 files changed
+67186
No files matched your search
@@ -0,0 +1,188 @@
|
||||
import React, { useState } from 'react';
|
||||
import { CycleFeedInitialBalance } from '../../types/counting.ts';
|
||||
import { formatNumber } from '../../utils/formatters.ts';
|
||||
|
||||
interface InitialBalanceCardProps {
|
||||
cycleId: string;
|
||||
initialBalance: CycleFeedInitialBalance | null;
|
||||
onSave: (saldoAwal: number) => Promise<void>;
|
||||
}
|
||||
|
||||
const InitialBalanceCard: React.FC<InitialBalanceCardProps> = ({
|
||||
cycleId: _cycleId,
|
||||
initialBalance,
|
||||
onSave,
|
||||
}) => {
|
||||
const [isEditing, setIsEditing] = useState(false);
|
||||
const [editValue, setEditValue] = useState<number>(initialBalance?.saldoAwal || 0);
|
||||
const [validationError, setValidationError] = useState<string>('');
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
const handleEdit = () => {
|
||||
setEditValue(initialBalance?.saldoAwal || 0);
|
||||
setValidationError('');
|
||||
setIsEditing(true);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
setIsEditing(false);
|
||||
setEditValue(initialBalance?.saldoAwal || 0);
|
||||
setValidationError('');
|
||||
};
|
||||
|
||||
const handleSave = async () => {
|
||||
// Validation
|
||||
if (editValue < 0) {
|
||||
setValidationError('Saldo awal tidak boleh negatif');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!Number.isInteger(editValue)) {
|
||||
setValidationError('Saldo awal harus bilangan bulat');
|
||||
return;
|
||||
}
|
||||
|
||||
setIsSaving(true);
|
||||
try {
|
||||
await onSave(editValue);
|
||||
setIsEditing(false);
|
||||
setValidationError('');
|
||||
} catch (error) {
|
||||
console.error('Failed to save initial balance:', error);
|
||||
setValidationError('Gagal menyimpan. Coba lagi.');
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
const formatLastUpdate = () => {
|
||||
if (!initialBalance) return null;
|
||||
|
||||
const date = new Date(initialBalance.updatedAt);
|
||||
|
||||
// Check if date is valid
|
||||
if (isNaN(date.getTime())) {
|
||||
return null; // Return null if date is invalid, won't show the update info
|
||||
}
|
||||
|
||||
const formattedDate = date.toLocaleDateString('id-ID', {
|
||||
day: 'numeric',
|
||||
month: 'short',
|
||||
year: 'numeric',
|
||||
});
|
||||
const formattedTime = date.toLocaleTimeString('id-ID', {
|
||||
hour: '2-digit',
|
||||
minute: '2-digit',
|
||||
});
|
||||
|
||||
return `${formattedDate} ${formattedTime}${initialBalance.createdBy ? ` oleh ${initialBalance.createdBy}` : ''}`;
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-gradient-to-br from-blue-50 to-indigo-50 p-6 rounded-xl shadow-sm border-2 border-blue-200">
|
||||
<div className="flex items-center justify-between mb-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="bg-blue-500 text-white p-3 rounded-lg">
|
||||
<i className="fa-solid fa-box-archive text-2xl"></i>
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="text-xl font-bold text-gray-800">Saldo Karung Awal</h2>
|
||||
<p className="text-sm text-gray-600">Stok awal karung pakan untuk siklus ini</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!isEditing && (
|
||||
<button
|
||||
onClick={handleEdit}
|
||||
className="px-4 py-2 bg-blue-500 text-white rounded-lg hover:bg-blue-600 transition-colors flex items-center gap-2"
|
||||
>
|
||||
<i className="fa-solid fa-edit"></i>
|
||||
<span>Edit</span>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="bg-white rounded-lg p-6 border border-blue-200">
|
||||
{isEditing ? (
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<div className="flex items-center gap-3">
|
||||
<input
|
||||
type="number"
|
||||
value={editValue}
|
||||
onChange={(e) => setEditValue(parseInt(e.target.value) || 0)}
|
||||
className="flex-1 px-4 py-3 border-2 border-blue-300 rounded-lg text-2xl font-bold text-gray-800 focus:outline-none focus:border-blue-500"
|
||||
placeholder="0"
|
||||
min="0"
|
||||
step="1"
|
||||
/>
|
||||
<span className="text-gray-600 font-semibold">karung</span>
|
||||
</div>
|
||||
{validationError && (
|
||||
<p className="text-sm text-red-600 mt-2">
|
||||
<i className="fa-solid fa-exclamation-circle mr-1"></i>
|
||||
{validationError}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2">
|
||||
<button
|
||||
onClick={handleSave}
|
||||
disabled={isSaving}
|
||||
className="flex-1 px-4 py-2 bg-green-500 text-white rounded-lg hover:bg-green-600 disabled:opacity-50 transition-colors"
|
||||
>
|
||||
{isSaving ? (
|
||||
<>
|
||||
<i className="fa-solid fa-spinner fa-spin mr-2"></i>
|
||||
Menyimpan...
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<i className="fa-solid fa-check mr-2"></i>
|
||||
Simpan
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
<button
|
||||
onClick={handleCancel}
|
||||
disabled={isSaving}
|
||||
className="flex-1 px-4 py-2 bg-gray-500 text-white rounded-lg hover:bg-gray-600 disabled:opacity-50 transition-colors"
|
||||
>
|
||||
<i className="fa-solid fa-times mr-2"></i>
|
||||
Batal
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-center">
|
||||
{initialBalance && initialBalance.saldoAwal > 0 ? (
|
||||
<>
|
||||
<p className="text-5xl font-bold text-blue-600 mb-2">
|
||||
{formatNumber(initialBalance.saldoAwal)}
|
||||
</p>
|
||||
<p className="text-lg text-gray-600 mb-3">karung</p>
|
||||
{formatLastUpdate() && (
|
||||
<p className="text-xs text-gray-500">
|
||||
<i className="fa-solid fa-clock mr-1"></i>
|
||||
Terakhir diperbarui: {formatLastUpdate()}
|
||||
</p>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<div className="py-4">
|
||||
<i className="fa-solid fa-inbox text-5xl text-gray-300 mb-3"></i>
|
||||
<p className="text-lg font-semibold text-gray-600 mb-1">
|
||||
Saldo karung awal belum diatur
|
||||
</p>
|
||||
<p className="text-sm text-gray-500">Klik Edit untuk menambahkan</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default InitialBalanceCard;
|
||||
Reference in new issue
Block a user