summaryrefslogtreecommitdiff
path: root/lib/general-contracts_old/detail/general-contract-field-service-rate.tsx
diff options
context:
space:
mode:
authorTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2025-11-10 11:25:19 +0900
committerTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2025-11-10 11:25:19 +0900
commita5501ad1d1cb836d2b2f84e9b0f06049e22c901e (patch)
tree667ed8c5d6ec35b109190e9f976d66ae54def4ce /lib/general-contracts_old/detail/general-contract-field-service-rate.tsx
parentb0fe980376fcf1a19ff4b90851ca8b01f378fdc0 (diff)
parentf8a38907911d940cb2e8e6c9aa49488d05b2b578 (diff)
Merge remote-tracking branch 'origin/dujinkim' into master_homemaster
Diffstat (limited to 'lib/general-contracts_old/detail/general-contract-field-service-rate.tsx')
-rw-r--r--lib/general-contracts_old/detail/general-contract-field-service-rate.tsx288
1 files changed, 288 insertions, 0 deletions
diff --git a/lib/general-contracts_old/detail/general-contract-field-service-rate.tsx b/lib/general-contracts_old/detail/general-contract-field-service-rate.tsx
new file mode 100644
index 00000000..a8158307
--- /dev/null
+++ b/lib/general-contracts_old/detail/general-contract-field-service-rate.tsx
@@ -0,0 +1,288 @@
+'use client'
+
+import React, { useState, useEffect } from 'react'
+import { useSession } from 'next-auth/react'
+import { Input } from '@/components/ui/input'
+import { Button } from '@/components/ui/button'
+import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from '@/components/ui/accordion'
+import { Checkbox } from '@/components/ui/checkbox'
+import { Plus, Trash2, Save, LoaderIcon, DollarSign } from 'lucide-react'
+import { getFieldServiceRate, updateFieldServiceRate } from '../service'
+import { toast } from 'sonner'
+
+interface FieldServiceRateProps {
+ contractId: number
+ contractType?: string
+}
+
+interface FieldServiceRateItem {
+ id: string
+ levelOfSpecialist: string
+ description: string
+ rateCurrency: string
+ onshoreRate: string
+ offshoreRate: string
+ rateUnit: string
+ remark: string
+}
+
+export function FieldServiceRate({ contractId }: FieldServiceRateProps) {
+ const session = useSession()
+ const [isLoading, setIsLoading] = useState(false)
+ const [isEnabled, setIsEnabled] = useState(true)
+
+ // 특정 계약종류를 제외한 일반계약은 Default로 표시
+ const isDisabled = false
+
+ const [fieldServiceRates, setFieldServiceRates] = useState<FieldServiceRateItem[]>([])
+
+ // 초기 데이터 로드
+ useEffect(() => {
+ const loadFieldServiceRate = async () => {
+ try {
+ const data = await getFieldServiceRate(contractId)
+ if (data && data.enabled !== undefined) {
+ setIsEnabled(data.enabled)
+ setFieldServiceRates(data.fieldServiceRates || [])
+ } else {
+ }
+ } catch (error) {
+ console.error('Field Service Rate 데이터 로드 실패:', error)
+ toast.error('Field Service Rate 데이터를 불러오는데 실패했습니다.')
+ }
+ }
+
+ loadFieldServiceRate()
+ }, [contractId])
+
+ const addFieldServiceRateRow = () => {
+ const newRow: FieldServiceRateItem = {
+ id: Date.now().toString(),
+ levelOfSpecialist: '',
+ description: '',
+ rateCurrency: 'USD',
+ onshoreRate: '',
+ offshoreRate: '',
+ rateUnit: 'day',
+ remark: ''
+ }
+ setFieldServiceRates([...fieldServiceRates, newRow])
+ }
+
+ const removeFieldServiceRateRow = (id: string) => {
+ setFieldServiceRates(fieldServiceRates.filter(item => item.id !== id))
+ }
+
+ const updateFieldServiceRateData = (id: string, field: keyof FieldServiceRateItem, value: string) => {
+ setFieldServiceRates(prev =>
+ prev.map(item =>
+ item.id === id ? { ...item, [field]: value } : item
+ )
+ )
+ }
+
+ const handleSaveFieldServiceRate = async () => {
+ if (!session.data?.user?.id) {
+ toast.error('로그인이 필요합니다.')
+ return
+ }
+
+ setIsLoading(true)
+ try {
+ const fieldServiceRateData = {
+ enabled: isEnabled,
+ fieldServiceRates: fieldServiceRates
+ }
+
+ await updateFieldServiceRate(contractId, fieldServiceRateData, Number(session.data.user.id))
+ toast.success('Field Service Rate가 성공적으로 저장되었습니다.')
+ } catch (error) {
+ console.error('Field Service Rate 저장 실패:', error)
+ toast.error('Field Service Rate 저장에 실패했습니다.')
+ } finally {
+ setIsLoading(false)
+ }
+ }
+
+ return (
+ <div className="w-full">
+ <Accordion type="single" collapsible className="w-full">
+ <AccordionItem value="field-service-rate">
+ <AccordionTrigger className="hover:no-underline">
+ <div className="flex items-center gap-3 w-full">
+ <DollarSign className="w-5 h-5" />
+ <span className="font-medium">Field Service Rate</span>
+ </div>
+ </AccordionTrigger>
+ <AccordionContent>
+ <div className="space-y-6">
+ {/* 체크박스 */}
+ <div className="flex items-center gap-2">
+ <Checkbox
+ checked={isEnabled}
+ disabled={isDisabled}
+ onCheckedChange={(checked) => {
+ if (!isDisabled) {
+ setIsEnabled(checked as boolean)
+ }
+ }}
+ />
+ <span className="text-sm font-medium">Field Service Rate 활성화</span>
+ </div>
+
+ {/* Field Service Rate 테이블 */}
+ <div className="space-y-4">
+ <div className="flex items-center justify-between">
+ <h3 className="text-lg font-medium">Field Service Rate</h3>
+ <div className="flex gap-2">
+ <Button
+ type="button"
+ variant="outline"
+ size="sm"
+ onClick={addFieldServiceRateRow}
+ disabled={isDisabled || !isEnabled}
+ className="flex items-center gap-2"
+ >
+ <Plus className="w-4 h-4" />
+ 행 추가
+ </Button>
+ <Button
+ type="button"
+ variant="outline"
+ size="sm"
+ onClick={() => {
+ if (confirm('선택된 행들을 삭제하시겠습니까?')) {
+ // 선택된 행들 삭제 로직 (필요시 구현)
+ }
+ }}
+ disabled={isDisabled || !isEnabled}
+ className="flex items-center gap-2"
+ >
+ <Trash2 className="w-4 h-4" />
+ 행 삭제
+ </Button>
+ </div>
+ </div>
+
+ <div className="overflow-x-auto">
+ <table className={`w-full border-collapse border border-gray-300 ${!isEnabled ? 'opacity-50' : ''}`}>
+ <thead>
+ <tr className="bg-yellow-100">
+ <th className="border border-gray-300 p-2 w-16">No.</th>
+ <th className="border border-gray-300 p-2 w-40">Level of Specialist</th>
+ <th className="border border-gray-300 p-2">Description</th>
+ <th className="border border-gray-300 p-2 w-32">Rate Currency</th>
+ <th className="border border-gray-300 p-2 w-32">Onshore Rate</th>
+ <th className="border border-gray-300 p-2 w-32">Offshore Rate</th>
+ <th className="border border-gray-300 p-2 w-24">Rate Unit</th>
+ <th className="border border-gray-300 p-2 w-32">Remark</th>
+ <th className="border border-gray-300 p-2 w-20">Action</th>
+ </tr>
+ </thead>
+ <tbody>
+ {fieldServiceRates.map((item, index) => (
+ <tr key={item.id} className="bg-yellow-50">
+ <td className="border border-gray-300 p-2 text-center">{index + 1}</td>
+ <td className="border border-gray-300 p-2">
+ <Input
+ value={item.levelOfSpecialist}
+ onChange={(e) => updateFieldServiceRateData(item.id, 'levelOfSpecialist', e.target.value)}
+ disabled={isDisabled || !isEnabled}
+ className="border-0 bg-transparent p-0 h-auto"
+ />
+ </td>
+ <td className="border border-gray-300 p-2">
+ <Input
+ value={item.description}
+ onChange={(e) => updateFieldServiceRateData(item.id, 'description', e.target.value)}
+ disabled={isDisabled || !isEnabled}
+ className="border-0 bg-transparent p-0 h-auto"
+ />
+ </td>
+ <td className="border border-gray-300 p-2">
+ <Input
+ value={item.rateCurrency}
+ onChange={(e) => updateFieldServiceRateData(item.id, 'rateCurrency', e.target.value)}
+ disabled={isDisabled || !isEnabled}
+ className="border-0 bg-transparent p-0 h-auto"
+ />
+ </td>
+ <td className="border border-gray-300 p-2">
+ <Input
+ value={item.onshoreRate}
+ onChange={(e) => updateFieldServiceRateData(item.id, 'onshoreRate', e.target.value)}
+ disabled={isDisabled || !isEnabled}
+ className="border-0 bg-transparent p-0 h-auto"
+ />
+ </td>
+ <td className="border border-gray-300 p-2">
+ <Input
+ value={item.offshoreRate}
+ onChange={(e) => updateFieldServiceRateData(item.id, 'offshoreRate', e.target.value)}
+ disabled={isDisabled || !isEnabled}
+ className="border-0 bg-transparent p-0 h-auto"
+ />
+ </td>
+ <td className="border border-gray-300 p-2">
+ <Input
+ value={item.rateUnit}
+ onChange={(e) => updateFieldServiceRateData(item.id, 'rateUnit', e.target.value)}
+ disabled={isDisabled || !isEnabled}
+ className="border-0 bg-transparent p-0 h-auto"
+ />
+ </td>
+ <td className="border border-gray-300 p-2">
+ <Input
+ value={item.remark}
+ onChange={(e) => updateFieldServiceRateData(item.id, 'remark', e.target.value)}
+ disabled={isDisabled || !isEnabled}
+ className="border-0 bg-transparent p-0 h-auto"
+ />
+ </td>
+ <td className="border border-gray-300 p-2 text-center">
+ <Button
+ type="button"
+ variant="ghost"
+ size="sm"
+ onClick={() => removeFieldServiceRateRow(item.id)}
+ disabled={isDisabled || !isEnabled}
+ className="h-8 w-8 p-0 text-red-600 hover:text-red-700"
+ >
+ <Trash2 className="w-4 h-4" />
+ </Button>
+ </td>
+ </tr>
+ ))}
+ </tbody>
+ </table>
+ </div>
+
+ {/* Note 정보 */}
+ <div className="space-y-2 text-sm text-gray-600">
+ <p><strong>Note #1:</strong> Air fare, travelling costs and hours, Visa, training, medical test and any additional applications are included.</p>
+ <p><strong>Note #2:</strong> Accommodation, meal and local transportation are included.</p>
+ </div>
+ </div>
+
+ {/* 저장 버튼 */}
+ <div className="flex justify-end pt-4 border-t">
+ <Button
+ onClick={handleSaveFieldServiceRate}
+ disabled={isLoading || isDisabled || !isEnabled}
+ className="flex items-center gap-2"
+ >
+ {isLoading ? (
+ <LoaderIcon className="w-4 h-4 animate-spin" />
+ ) : (
+ <Save className="w-4 h-4" />
+ )}
+ Field Service Rate 저장
+ </Button>
+ </div>
+ </div>
+ </AccordionContent>
+ </AccordionItem>
+ </Accordion>
+ </div>
+ )
+}