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:
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user