forked from StellarSplit/StellarSplit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathTaxTipStep.tsx
More file actions
121 lines (110 loc) · 5.97 KB
/
Copy pathTaxTipStep.tsx
File metadata and controls
121 lines (110 loc) · 5.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
import { useTranslation } from 'react-i18next';
import type { WizardState } from '../../../types/wizard';
interface TaxTipStepProps {
value: Pick<WizardState, 'taxAmount' | 'tipAmount' | 'totalAmount' | 'currency'>;
onChange: (patch: Partial<WizardState>) => void;
errors: Record<string, string>;
}
const QUICK_TIP_PERCENTAGES = [10, 15, 18, 20, 25];
export const TaxTipStep = ({ value, onChange, errors }: TaxTipStepProps) => {
const { t } = useTranslation();
const applyTipPercent = (pct: number) => {
onChange({ tipAmount: parseFloat(((value.totalAmount * pct) / 100).toFixed(2)) });
};
const grandTotal = value.totalAmount + value.taxAmount + value.tipAmount;
return (
<div className="space-y-6">
<div>
<h2 className="text-xl font-bold text-gray-900">{t('wizard.taxTip.title')}</h2>
<p className="text-sm text-gray-500 mt-1">{t('wizard.taxTip.subtitle')}</p>
</div>
{/* Tax */}
<div className="bg-white rounded-xl border border-gray-200 p-4 shadow-sm space-y-3">
<h3 className="text-sm font-semibold text-gray-700">{t('wizard.taxTip.taxLabel')}</h3>
<div className="relative">
<span className="absolute left-4 top-1/2 -translate-y-1/2 text-gray-400 text-sm">
{value.currency}
</span>
<input
type="number"
min="0"
step="0.01"
value={value.taxAmount === 0 ? '' : value.taxAmount}
onChange={(e) => onChange({ taxAmount: parseFloat(e.target.value) || 0 })}
placeholder="0.00"
className={`w-full pl-14 pr-4 py-3 rounded-xl border text-gray-900 placeholder-gray-400 bg-white focus:outline-none focus:ring-2 focus:ring-purple-400 transition-shadow
${errors.taxAmount ? 'border-red-400' : 'border-gray-200'}`}
/>
</div>
{errors.taxAmount && (
<p className="text-xs text-red-500">{errors.taxAmount}</p>
)}
</div>
{/* Tip */}
<div className="bg-white rounded-xl border border-gray-200 p-4 shadow-sm space-y-3">
<h3 className="text-sm font-semibold text-gray-700">{t('wizard.taxTip.tipLabel')}</h3>
{/* Quick-tip buttons */}
<div className="flex gap-2 flex-wrap">
{QUICK_TIP_PERCENTAGES.map((pct) => {
const tipValue = parseFloat(((value.totalAmount * pct) / 100).toFixed(2));
const isActive = Math.abs(value.tipAmount - tipValue) < 0.01;
return (
<button
key={pct}
type="button"
onClick={() => applyTipPercent(pct)}
className={`px-3 py-1.5 rounded-lg text-xs font-semibold border transition-all min-h-[36px]
${isActive
? 'bg-purple-500 text-white border-purple-500'
: 'bg-white text-gray-600 border-gray-200 hover:border-purple-300 hover:text-purple-600'
}`}
>
{pct}%
</button>
);
})}
<button
type="button"
onClick={() => onChange({ tipAmount: 0 })}
className="px-3 py-1.5 rounded-lg text-xs font-semibold border border-gray-200 text-gray-400 hover:text-red-500 hover:border-red-200 transition-all min-h-[36px]"
>
{t('wizard.taxTip.noTip')}
</button>
</div>
<div className="relative">
<span className="absolute left-4 top-1/2 -translate-y-1/2 text-gray-400 text-sm">
{value.currency}
</span>
<input
type="number"
min="0"
step="0.01"
value={value.tipAmount === 0 ? '' : value.tipAmount}
onChange={(e) => onChange({ tipAmount: parseFloat(e.target.value) || 0 })}
placeholder="0.00"
className="w-full pl-14 pr-4 py-3 rounded-xl border border-gray-200 text-gray-900 placeholder-gray-400 bg-white focus:outline-none focus:ring-2 focus:ring-purple-400 transition-shadow"
/>
</div>
</div>
{/* Grand total summary */}
<div className="bg-purple-50 rounded-xl border border-purple-100 p-4 space-y-2">
<div className="flex justify-between text-sm text-gray-600">
<span>{t('wizard.taxTip.subtotal')}</span>
<span>{value.currency} {value.totalAmount.toFixed(2)}</span>
</div>
<div className="flex justify-between text-sm text-gray-600">
<span>{t('wizard.taxTip.taxLabel')}</span>
<span>+ {value.currency} {value.taxAmount.toFixed(2)}</span>
</div>
<div className="flex justify-between text-sm text-gray-600">
<span>{t('wizard.taxTip.tipLabel')}</span>
<span>+ {value.currency} {value.tipAmount.toFixed(2)}</span>
</div>
<div className="flex justify-between text-base font-bold text-gray-900 pt-2 border-t border-purple-200">
<span>{t('wizard.taxTip.grandTotal')}</span>
<span>{value.currency} {grandTotal.toFixed(2)}</span>
</div>
</div>
</div>
);
};