feat: WCAG AA accessibility, code splitting, responsive ads layout

- Add React.lazy code splitting for all 15 tool pages
- Fix WCAG AA contrast issues (304 text color fixes)
- Add ARIA labels and aria-expanded to navigation buttons
- Add aria-live for error announcements in tools
- Implement responsive ad layout:
  - Desktop (≥1280px): Right sidebar with 3 ad units
  - Tablet (1024-1279px): Bottom section with 3 horizontal units
  - Mobile (<1024px): Fixed bottom banner
- Add TabletAdSection component for tablet ad placement
- Integrate Onidel affiliate partnership
- Update all Adsterra domains to solutionbiologyisle.com
- Add release notes for 2026-02-18 updates
This commit is contained in:
dwindown
2026-02-18 18:57:31 +07:00
parent 9dc3285adb
commit 3a475e9df2
41 changed files with 391 additions and 318 deletions

View File

@@ -777,7 +777,7 @@ const InvoiceEditor = () => {
className={`${
activeTab === tab.id
? 'border-blue-500 text-blue-600 dark:text-blue-400'
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 dark:text-gray-400 dark:hover:text-gray-300'
: 'border-transparent text-gray-600 hover:text-gray-700 hover:border-gray-300 dark:text-gray-600 dark:hover:text-gray-300'
} whitespace-nowrap py-4 px-1 sm:px-2 border-b-2 font-medium text-sm flex items-center gap-1 sm:gap-2 transition-colors min-w-0 flex-shrink-0`}
>
<Icon className="h-4 w-4" />
@@ -793,11 +793,11 @@ const InvoiceEditor = () => {
<div className="p-4">
{activeTab === 'create' && (
<div className="text-center py-12">
<FileText className="mx-auto h-12 w-12 text-gray-400 dark:text-gray-500 mb-4" />
<FileText className="mx-auto h-12 w-12 text-gray-600 dark:text-gray-600 mb-4" />
<h3 className="text-lg font-medium text-gray-900 dark:text-gray-100 mb-2">
Start Building Your Invoice
</h3>
<p className="text-gray-500 dark:text-gray-400 mb-8 max-w-md mx-auto">
<p className="text-gray-600 dark:text-gray-600 mb-8 max-w-md mx-auto">
Choose how you'd like to begin creating your professional invoice
</p>
@@ -813,11 +813,11 @@ const InvoiceEditor = () => {
}}
className="flex flex-col items-center p-6 border-2 border-dashed border-gray-300 dark:border-gray-600 rounded-lg hover:border-blue-500 dark:hover:border-blue-400 hover:bg-blue-50 dark:hover:bg-blue-900/20 transition-colors group"
>
<Plus className="h-8 w-8 text-gray-400 group-hover:text-blue-500 dark:group-hover:text-blue-400 mb-2" />
<Plus className="h-8 w-8 text-gray-600 group-hover:text-blue-500 dark:group-hover:text-blue-400 mb-2" />
<span className="font-medium text-gray-900 dark:text-gray-100 group-hover:text-blue-600 dark:group-hover:text-blue-400">
Start Empty
</span>
<span className="text-xs text-gray-500 dark:text-gray-400 text-center mt-1">
<span className="text-xs text-gray-600 dark:text-gray-600 text-center mt-1">
Create a blank invoice
</span>
</button>
@@ -833,11 +833,11 @@ const InvoiceEditor = () => {
}}
className="flex flex-col items-center p-6 border-2 border-dashed border-gray-300 dark:border-gray-600 rounded-lg hover:border-green-500 dark:hover:border-green-400 hover:bg-green-50 dark:hover:bg-green-900/20 transition-colors group"
>
<FileText className="h-8 w-8 text-gray-400 group-hover:text-green-500 dark:group-hover:text-green-400 mb-2" />
<FileText className="h-8 w-8 text-gray-600 group-hover:text-green-500 dark:group-hover:text-green-400 mb-2" />
<span className="font-medium text-gray-900 dark:text-gray-100 group-hover:text-green-600 dark:group-hover:text-green-400">
Load Sample
</span>
<span className="text-xs text-gray-500 dark:text-gray-400 text-center mt-1">
<span className="text-xs text-gray-600 dark:text-gray-600 text-center mt-1">
Start with example invoice
</span>
</button>
@@ -866,7 +866,7 @@ const InvoiceEditor = () => {
{isLoading ? 'Fetching...' : 'Fetch Data'}
</button>
</div>
<p className="text-xs text-gray-500 dark:text-gray-400">
<p className="text-xs text-gray-600 dark:text-gray-600">
Enter any URL that returns exported JSON data from your previous invoice work.
</p>
</div>
@@ -908,7 +908,7 @@ const InvoiceEditor = () => {
</div>
)}
<div className="flex items-center justify-between flex-shrink-0">
<div className="text-sm text-gray-600 dark:text-gray-400">
<div className="text-sm text-gray-600 dark:text-gray-600">
Supports JSON invoice templates
</div>
<button
@@ -985,9 +985,9 @@ const InvoiceEditor = () => {
<div className="p-4 sm:p-6 space-y-4 sm:space-y-6">
{!createNewCompleted ? (
<div className="text-center py-12">
<FileText className="mx-auto h-12 w-12 text-gray-400 mb-4" />
<FileText className="mx-auto h-12 w-12 text-gray-600 mb-4" />
<h3 className="text-lg font-medium text-gray-900 dark:text-white mb-2">No Invoice Data Loaded</h3>
<p className="text-gray-500 dark:text-gray-400">
<p className="text-gray-600 dark:text-gray-600">
Use the input section above to create a new invoice or load existing data.
</p>
</div>
@@ -1080,7 +1080,7 @@ const InvoiceEditor = () => {
'--tw-ring-color': `${invoiceData.settings?.colorScheme || '#3B82F6'}40`
}}
/>
<span className="text-xs text-gray-500 dark:text-gray-400">Show in preview</span>
<span className="text-xs text-gray-600 dark:text-gray-600">Show in preview</span>
</label>
</div>
@@ -1121,7 +1121,7 @@ const InvoiceEditor = () => {
className="flex-1 text-sm text-gray-600 dark:text-gray-300 bg-transparent border-0 border-b border-gray-200 dark:border-gray-600 focus:border-blue-500 focus:outline-none focus:ring-0 pb-1 disabled:cursor-not-allowed"
placeholder="Phone"
/>
<span className="text-gray-400 text-sm self-end pb-1 hidden sm:block">|</span>
<span className="text-gray-600 text-sm self-end pb-1 hidden sm:block">|</span>
<input
type="email"
value={invoiceData.company.email}
@@ -1173,7 +1173,7 @@ const InvoiceEditor = () => {
className="flex-1 text-sm text-gray-600 dark:text-gray-300 bg-transparent border-0 border-b border-gray-200 dark:border-gray-600 focus:border-green-500 focus:outline-none focus:ring-0 pb-1"
placeholder="Phone"
/>
<span className="text-gray-400 text-sm self-end pb-1 hidden sm:block">|</span>
<span className="text-gray-600 text-sm self-end pb-1 hidden sm:block">|</span>
<input
type="email"
value={invoiceData.client.email}
@@ -1233,7 +1233,7 @@ const InvoiceEditor = () => {
</td>
<td className="px-3 py-3 text-center" style={{ width: 'auto' }}>
<div className="relative flex justify-end items-center">
<span className="text-gray-500 dark:text-gray-400 px-2 py-1 text-xs rounded-1 bg-gray-100 dark:bg-gray-900/20">{invoiceData.settings?.currency?.symbol || '$'}</span>
<span className="text-gray-600 dark:text-gray-600 px-2 py-1 text-xs rounded-1 bg-gray-100 dark:bg-gray-900/20">{invoiceData.settings?.currency?.symbol || '$'}</span>
<input
type="text"
value={formatNumber(item.rate)}
@@ -1264,7 +1264,7 @@ const InvoiceEditor = () => {
<button
onClick={() => moveItem('items', item.id, 'up')}
disabled={index === 0}
className="p-1 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700/50 rounded transition-colors disabled:opacity-30 disabled:cursor-not-allowed"
className="p-1 text-gray-600 hover:text-gray-700 dark:text-gray-600 dark:hover:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700/50 rounded transition-colors disabled:opacity-30 disabled:cursor-not-allowed"
title="Move up"
>
<ChevronUp className="h-4 w-4" />
@@ -1272,7 +1272,7 @@ const InvoiceEditor = () => {
<button
onClick={() => moveItem('items', item.id, 'down')}
disabled={index === invoiceData.items.length - 1}
className="p-1 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700/50 rounded transition-colors disabled:opacity-30 disabled:cursor-not-allowed"
className="p-1 text-gray-600 hover:text-gray-700 dark:text-gray-600 dark:hover:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700/50 rounded transition-colors disabled:opacity-30 disabled:cursor-not-allowed"
title="Move down"
>
<ChevronDown className="h-4 w-4" />
@@ -1372,7 +1372,7 @@ const InvoiceEditor = () => {
<button
onClick={() => moveItem('fees', fee.id, 'up')}
disabled={index === 0}
className="p-2 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-600 rounded transition-colors disabled:opacity-30 disabled:cursor-not-allowed"
className="p-2 text-gray-600 hover:text-gray-700 dark:text-gray-600 dark:hover:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-600 rounded transition-colors disabled:opacity-30 disabled:cursor-not-allowed"
title="Move up"
>
<ChevronUp className="h-4 w-4" />
@@ -1380,7 +1380,7 @@ const InvoiceEditor = () => {
<button
onClick={() => moveItem('fees', fee.id, 'down')}
disabled={index === (invoiceData.fees || []).length - 1}
className="p-2 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-600 rounded transition-colors disabled:opacity-30 disabled:cursor-not-allowed"
className="p-2 text-gray-600 hover:text-gray-700 dark:text-gray-600 dark:hover:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-600 rounded transition-colors disabled:opacity-30 disabled:cursor-not-allowed"
title="Move down"
>
<ChevronDown className="h-4 w-4" />
@@ -1449,7 +1449,7 @@ const InvoiceEditor = () => {
<button
onClick={() => moveItem('discounts', discount.id, 'up')}
disabled={index === 0}
className="p-2 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-600 rounded transition-colors disabled:opacity-30 disabled:cursor-not-allowed"
className="p-2 text-gray-600 hover:text-gray-700 dark:text-gray-600 dark:hover:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-600 rounded transition-colors disabled:opacity-30 disabled:cursor-not-allowed"
title="Move up"
>
<ChevronUp className="h-4 w-4" />
@@ -1457,7 +1457,7 @@ const InvoiceEditor = () => {
<button
onClick={() => moveItem('discounts', discount.id, 'down')}
disabled={index === (invoiceData.discounts || []).length - 1}
className="p-2 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-600 rounded transition-colors disabled:opacity-30 disabled:cursor-not-allowed"
className="p-2 text-gray-600 hover:text-gray-700 dark:text-gray-600 dark:hover:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-600 rounded transition-colors disabled:opacity-30 disabled:cursor-not-allowed"
title="Move down"
>
<ChevronDown className="h-4 w-4" />
@@ -1484,14 +1484,14 @@ const InvoiceEditor = () => {
</h3>
<div className="space-y-3">
<div className="flex justify-between items-center py-2 border-b border-emerald-200 dark:border-emerald-700">
<span className="text-gray-600 dark:text-gray-400">Subtotal:</span>
<span className="text-gray-600 dark:text-gray-600">Subtotal:</span>
<span className="font-medium text-gray-900 dark:text-white flex-shrink-0">{formatCurrency(invoiceData.subtotal, true)}</span>
</div>
{/* Dynamic Fees */}
{(invoiceData.fees || []).map((fee) => (
<div key={fee.id} className="flex justify-between items-center py-2 border-b border-emerald-200 dark:border-emerald-700">
<span className="text-gray-600 dark:text-gray-400">
<span className="text-gray-600 dark:text-gray-600">
{fee.label || 'Fee'} {fee.type === 'percentage' ? `(${fee.value}%)` : ''}:
</span>
<span className="font-medium text-blue-600 dark:text-blue-400 flex-shrink-0">
@@ -1503,7 +1503,7 @@ const InvoiceEditor = () => {
{/* Dynamic Discounts */}
{(invoiceData.discounts || []).map((discount) => (
<div key={discount.id} className="flex justify-between items-center py-2 border-b border-emerald-200 dark:border-emerald-700">
<span className="text-gray-600 dark:text-gray-400">
<span className="text-gray-600 dark:text-gray-600">
{discount.label || 'Discount'} {discount.type === 'percentage' ? `(${discount.value}%)` : ''}:
</span>
<span className="font-medium text-red-600 dark:text-red-400 flex-shrink-0">
@@ -1515,7 +1515,7 @@ const InvoiceEditor = () => {
{/* Legacy Discount */}
{invoiceData.discount > 0 && (
<div className="flex justify-between items-center py-2 border-b border-emerald-200 dark:border-emerald-700">
<span className="text-gray-600 dark:text-gray-400">Discount:</span>
<span className="text-gray-600 dark:text-gray-600">Discount:</span>
<span className="font-medium text-red-600 dark:text-red-400 flex-shrink-0">-{formatCurrency(invoiceData.discount, true)}</span>
</div>
)}
@@ -1819,7 +1819,7 @@ const InvoiceEditor = () => {
<button
onClick={() => moveInstallment(installment.id, 'up')}
disabled={index === 0}
className="p-2 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-600 rounded transition-colors disabled:opacity-30 disabled:cursor-not-allowed"
className="p-2 text-gray-600 hover:text-gray-700 dark:text-gray-600 dark:hover:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-600 rounded transition-colors disabled:opacity-30 disabled:cursor-not-allowed"
title="Move up"
>
<ChevronUp className="h-4 w-4" />
@@ -1827,7 +1827,7 @@ const InvoiceEditor = () => {
<button
onClick={() => moveInstallment(installment.id, 'down')}
disabled={index === (invoiceData.paymentTerms?.installments || []).length - 1}
className="p-2 text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-600 rounded transition-colors disabled:opacity-30 disabled:cursor-not-allowed"
className="p-2 text-gray-600 hover:text-gray-700 dark:text-gray-600 dark:hover:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-600 rounded transition-colors disabled:opacity-30 disabled:cursor-not-allowed"
title="Move down"
>
<ChevronDown className="h-4 w-4" />
@@ -1956,7 +1956,7 @@ const InvoiceEditor = () => {
onChange={handleSignatureUpload}
className="hidden"
/>
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
<p className="text-xs text-gray-600 dark:text-gray-600 mt-1">
Upload an image of your signature (PNG, JPG recommended)
</p>
</div>
@@ -2227,7 +2227,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
<h3 className="text-lg font-semibold text-gray-900 dark:text-white">Invoice Settings</h3>
<button
onClick={onClose}
className="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300"
className="text-gray-600 hover:text-gray-600 dark:hover:text-gray-300"
>
<svg className="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M6 18L18 6M6 6l12 12" />
@@ -2242,7 +2242,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
className={`px-6 py-3 text-sm font-medium relative transition-all duration-200 ${
activeTab === 'general'
? 'text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/20'
: 'text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700/50'
: 'text-gray-600 hover:text-gray-700 dark:text-gray-600 dark:hover:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700/50'
}`}
>
General
@@ -2255,7 +2255,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
className={`px-6 py-3 text-sm font-medium relative transition-all duration-200 ${
activeTab === 'layout'
? 'text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/20'
: 'text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700/50'
: 'text-gray-600 hover:text-gray-700 dark:text-gray-600 dark:hover:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700/50'
}`}
>
Layout
@@ -2268,7 +2268,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
className={`px-6 py-3 text-sm font-medium relative transition-all duration-200 ${
activeTab === 'payment'
? 'text-blue-600 dark:text-blue-400 bg-blue-50 dark:bg-blue-900/20'
: 'text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700/50'
: 'text-gray-600 hover:text-gray-700 dark:text-gray-600 dark:hover:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-700/50'
}`}
>
Payment
@@ -2335,10 +2335,10 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
className="w-12 h-12 rounded-lg border border-gray-300 cursor-pointer bg-transparent"
/>
<div>
<p className="text-sm text-gray-600 dark:text-gray-400">
<p className="text-sm text-gray-600 dark:text-gray-600">
This color will be used throughout the invoice and PDF
</p>
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
<p className="text-xs text-gray-600 dark:text-gray-600 mt-1">
Current: {invoiceData.settings?.colorScheme || '#3B82F6'}
</p>
</div>
@@ -2355,7 +2355,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
selectedCurrency={invoiceData.settings?.currency}
onSelect={(currency) => onUpdateSettings('currency', currency)}
/>
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
<p className="text-xs text-gray-600 dark:text-gray-600 mt-1">
Selected: {invoiceData.settings?.currency?.symbol || invoiceData.settings?.currency?.code || '$'} ({invoiceData.settings?.currency?.code || 'USD'})
</p>
</div>
@@ -2373,7 +2373,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
<span className="text-sm font-medium text-gray-700 dark:text-gray-300">
Use Thousand Separator
</span>
<p className="text-xs text-gray-500 dark:text-gray-500">
<p className="text-xs text-gray-600 dark:text-gray-600">
Format numbers like 1,000.00 instead of 1000.00
</p>
</div>
@@ -2395,7 +2395,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
<option value={2}>2 (1000.00)</option>
<option value={3}>3 (1000.000)</option>
</select>
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
<p className="text-xs text-gray-600 dark:text-gray-600 mt-1">
Number of decimal places to display
</p>
</div>
@@ -2420,7 +2420,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
<option value="normal">Normal (25px spacing)</option>
<option value="spacious">Spacious (40px spacing)</option>
</select>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-1">
<p className="text-xs text-gray-600 dark:text-gray-600 mt-1">
Controls the spacing between major sections for better multi-page layout
</p>
</div>
@@ -2468,7 +2468,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
<span className="text-sm text-gray-700 dark:text-gray-300">Force page break before Payment Method</span>
</label>
</div>
<p className="text-xs text-gray-500 dark:text-gray-400 mt-2">
<p className="text-xs text-gray-600 dark:text-gray-600 mt-2">
Use page breaks to ensure important sections start on a new page in PDF output
</p>
</div>
@@ -2493,7 +2493,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
<option value="link">Payment Link</option>
<option value="qr">QR Code</option>
</select>
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
<p className="text-xs text-gray-600 dark:text-gray-600 mt-1">
Choose how payment information appears on your invoice
</p>
</div>
@@ -2505,7 +2505,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
<h4 className="text-sm font-medium text-gray-900 dark:text-white mb-3">Bank Details</h4>
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
<div>
<label className="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">
<label className="block text-xs font-medium text-gray-600 dark:text-gray-600 mb-1">
Bank Name
</label>
<input
@@ -2517,7 +2517,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
/>
</div>
<div>
<label className="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">
<label className="block text-xs font-medium text-gray-600 dark:text-gray-600 mb-1">
Account Name
</label>
<input
@@ -2529,7 +2529,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
/>
</div>
<div>
<label className="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">
<label className="block text-xs font-medium text-gray-600 dark:text-gray-600 mb-1">
Account Number
</label>
<input
@@ -2541,7 +2541,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
/>
</div>
<div>
<label className="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">
<label className="block text-xs font-medium text-gray-600 dark:text-gray-600 mb-1">
Routing Number
</label>
<input
@@ -2553,7 +2553,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
/>
</div>
<div>
<label className="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">
<label className="block text-xs font-medium text-gray-600 dark:text-gray-600 mb-1">
SWIFT Code
</label>
<input
@@ -2565,7 +2565,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
/>
</div>
<div>
<label className="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">
<label className="block text-xs font-medium text-gray-600 dark:text-gray-600 mb-1">
IBAN
</label>
<input
@@ -2586,7 +2586,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
<h4 className="text-sm font-medium text-gray-900 dark:text-white mb-3">Payment Link</h4>
<div className="space-y-3">
<div>
<label className="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">
<label className="block text-xs font-medium text-gray-600 dark:text-gray-600 mb-1">
Payment URL
</label>
<input
@@ -2598,7 +2598,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
/>
</div>
<div>
<label className="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">
<label className="block text-xs font-medium text-gray-600 dark:text-gray-600 mb-1">
Button Label
</label>
<input
@@ -2620,7 +2620,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
{/* QR Code Type Selection */}
<div className="mb-3">
<label className="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-2">
<label className="block text-xs font-medium text-gray-600 dark:text-gray-600 mb-2">
QR Code Type
</label>
<div className="flex gap-4">
@@ -2653,7 +2653,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
{invoiceData.paymentMethod?.qrCode?.customImage === undefined && (
<div className="space-y-3">
<div>
<label className="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">
<label className="block text-xs font-medium text-gray-600 dark:text-gray-600 mb-1">
Payment URL
</label>
<input
@@ -2664,7 +2664,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
placeholder="https://pay.stripe.com/..."
/>
</div>
<p className="text-xs text-gray-500 dark:text-gray-500">
<p className="text-xs text-gray-600 dark:text-gray-600">
QR code will be automatically generated from this URL
</p>
</div>
@@ -2674,7 +2674,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
{invoiceData.paymentMethod?.qrCode?.customImage !== undefined && (
<div className="space-y-3">
<div>
<label className="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">
<label className="block text-xs font-medium text-gray-600 dark:text-gray-600 mb-1">
Upload QR Code Image
</label>
<div className="flex items-center gap-3">
@@ -2724,7 +2724,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
{/* Common QR Code Label */}
<div className="mt-3">
<label className="block text-xs font-medium text-gray-600 dark:text-gray-400 mb-1">
<label className="block text-xs font-medium text-gray-600 dark:text-gray-600 mb-1">
QR Code Label
</label>
<input
@@ -2755,7 +2755,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
<option value="OVERDUE">OVERDUE</option>
<option value="PENDING">PENDING</option>
</select>
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
<p className="text-xs text-gray-600 dark:text-gray-600 mt-1">
Add a status stamp to your invoice PDF
</p>
</div>
@@ -2772,7 +2772,7 @@ const InvoiceSettingsModal = ({ invoiceData, currencies, onUpdateSettings, onClo
onChange={(e) => onUpdateSettings('paymentDate', e.target.value)}
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 dark:bg-gray-700 dark:text-white"
/>
<p className="text-xs text-gray-500 dark:text-gray-500 mt-1">
<p className="text-xs text-gray-600 dark:text-gray-600 mt-1">
Date when payment was received
</p>
</div>
@@ -2836,7 +2836,7 @@ const InputChangeConfirmationModal = ({ invoiceData, currentMethod, newMethod, o
<div className="px-6 py-4">
<div className="space-y-3">
<p className="text-sm text-gray-600 dark:text-gray-400">
<p className="text-sm text-gray-600 dark:text-gray-600">
You currently have:
</p>
<ul className="text-sm text-gray-700 dark:text-gray-300 space-y-1 ml-4">
@@ -2946,7 +2946,7 @@ const SignaturePadModal = ({ isOpen, onClose, onSave }) => {
/>
</div>
<p className="text-sm text-gray-600 dark:text-gray-400 mb-4">
<p className="text-sm text-gray-600 dark:text-gray-600 mb-4">
Draw your signature in the box above using your mouse or touch device.
</p>