Initial commit
This commit is contained in:
@@ -0,0 +1,189 @@
|
||||
import React, { useState, useEffect, useCallback } from 'react';
|
||||
import { View, Text, TouchableOpacity, TextInput } from 'react-native';
|
||||
import { Plus, Trash2, CheckCircle2 } from 'lucide-react-native';
|
||||
import GenericDropdown from './GenericDropdown';
|
||||
import api from '@/utils/api';
|
||||
import { useAlert } from './AlertComponent';
|
||||
|
||||
interface LaborItem {
|
||||
id_registry: number;
|
||||
id_user: number | null;
|
||||
name: string;
|
||||
hours: string | number;
|
||||
minutes: string | number;
|
||||
sync?: boolean;
|
||||
id?: number;
|
||||
}
|
||||
|
||||
interface ActivityLaborCardProps {
|
||||
title: string;
|
||||
fetchUrl: string;
|
||||
laborList: LaborItem[];
|
||||
onAddLabor: (labor: LaborItem) => void;
|
||||
onRemoveLabor: (index: number) => void;
|
||||
}
|
||||
|
||||
export default function ActivityLaborCard({
|
||||
title,
|
||||
fetchUrl,
|
||||
laborList,
|
||||
onAddLabor,
|
||||
onRemoveLabor
|
||||
}: ActivityLaborCardProps) {
|
||||
const alert = useAlert();
|
||||
const [items, setItems] = useState<any[]>([]);
|
||||
const [showInput, setShowInput] = useState(false);
|
||||
|
||||
// Form states
|
||||
const [selectedId, setSelectedId] = useState<number | null>(null);
|
||||
const [hours, setHours] = useState('');
|
||||
const [minutes, setMinutes] = useState('');
|
||||
|
||||
const loadItems = useCallback(async () => {
|
||||
try {
|
||||
const res = await api.get(fetchUrl);
|
||||
if (res.data?.success && res.data.items) {
|
||||
// Map the items to include an 'id' property required by GenericDropdown
|
||||
const mappedItems = res.data.items.map((item: any) => ({
|
||||
...item,
|
||||
id: item.id_registry
|
||||
}));
|
||||
setItems(mappedItems);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching labor items:', error);
|
||||
}
|
||||
}, [fetchUrl]);
|
||||
|
||||
useEffect(() => {
|
||||
loadItems();
|
||||
}, [loadItems]);
|
||||
|
||||
const handleAdd = () => {
|
||||
if (!selectedId) {
|
||||
alert.showAlert('error', 'Attenzione', 'Selezionare un elemento dalla lista');
|
||||
return;
|
||||
}
|
||||
|
||||
if (hours === '' && minutes === '') {
|
||||
alert.showAlert('error', 'Attenzione', 'Inserire le ore o i minuti di lavoro');
|
||||
return;
|
||||
}
|
||||
|
||||
const el = items.find(data => data.id_registry === selectedId);
|
||||
if (el) {
|
||||
const newLabor: LaborItem = {
|
||||
id_registry: selectedId,
|
||||
id_user: el.id_user,
|
||||
name: el.label,
|
||||
hours: hours === '' ? '0' : hours,
|
||||
minutes: minutes === '' ? '0' : minutes,
|
||||
};
|
||||
onAddLabor(newLabor);
|
||||
|
||||
// Reset and hide
|
||||
setSelectedId(null);
|
||||
setHours('');
|
||||
setMinutes('');
|
||||
setShowInput(false);
|
||||
}
|
||||
};
|
||||
|
||||
const toggleInput = () => {
|
||||
setSelectedId(null);
|
||||
setHours('');
|
||||
setMinutes('');
|
||||
setShowInput(!showInput);
|
||||
};
|
||||
|
||||
return (
|
||||
<View className="bg-white rounded-3xl p-5 shadow-sm border border-gray-100 mb-4">
|
||||
<View className="flex-row items-center justify-between border-b border-gray-50 pb-3 mb-3">
|
||||
<Text className="text-[#082963] font-bold text-lg">{title}</Text>
|
||||
<TouchableOpacity onPress={toggleInput} className="active:opacity-70">
|
||||
<Text className="text-[#1071C2] font-bold text-sm">
|
||||
{showInput ? 'Annulla' : 'Aggiungi'}
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{showInput && (
|
||||
<View className="bg-blue-50/50 p-4 rounded-2xl mb-4 border border-blue-100">
|
||||
<View className="mb-3 z-50">
|
||||
<GenericDropdown
|
||||
options={items}
|
||||
selectedId={selectedId}
|
||||
onSelect={(id) => setSelectedId(id as number)}
|
||||
placeholder="Seleziona..."
|
||||
searchPlaceholder="Cerca per nome"
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View className="flex-row items-center gap-2">
|
||||
<View className="flex-1 bg-white rounded-xl border border-gray-200 px-3 py-2">
|
||||
<TextInput
|
||||
value={hours}
|
||||
onChangeText={setHours}
|
||||
placeholder="Ore"
|
||||
placeholderTextColor="#9ca3af"
|
||||
keyboardType="numeric"
|
||||
className="text-gray-800 font-medium"
|
||||
/>
|
||||
</View>
|
||||
<View className="flex-1 bg-white rounded-xl border border-gray-200 px-3 py-2">
|
||||
<TextInput
|
||||
value={minutes}
|
||||
onChangeText={setMinutes}
|
||||
placeholder="Minuti"
|
||||
placeholderTextColor="#9ca3af"
|
||||
keyboardType="numeric"
|
||||
className="text-gray-800 font-medium"
|
||||
/>
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
onPress={handleAdd}
|
||||
className="bg-[#1071C2] h-[46px] w-[46px] items-center justify-center rounded-xl"
|
||||
>
|
||||
<Plus size={24} color="white" />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
</View>
|
||||
)}
|
||||
|
||||
<View className="gap-2">
|
||||
{laborList.map((item, index) => (
|
||||
<View key={index} className="flex-row justify-between items-center bg-gray-50 p-3 rounded-2xl">
|
||||
<Text className="text-gray-800 font-medium flex-1 mr-2" numberOfLines={2}>
|
||||
{item.name}
|
||||
</Text>
|
||||
|
||||
<View className="flex-row items-center gap-3">
|
||||
<View className="bg-white px-3 py-1.5 rounded-xl border border-gray-200">
|
||||
<Text className="text-[#1071C2] font-bold">
|
||||
{item.hours}h {item.minutes}m
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
{item.sync ? (
|
||||
<View className="w-8 items-center justify-center">
|
||||
<CheckCircle2 size={20} color="#0F9D58" />
|
||||
</View>
|
||||
) : (
|
||||
<TouchableOpacity
|
||||
onPress={() => onRemoveLabor(index)}
|
||||
className="w-8 items-center justify-center"
|
||||
>
|
||||
<Trash2 size={20} color="#ef4444" />
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
))}
|
||||
|
||||
{laborList.length === 0 && !showInput && (
|
||||
<Text className="text-gray-400 text-center italic mt-2">Nessun elemento inserito</Text>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user