feat: Add Spotify-style backdrop, Cascade OCR, Smart Scan Flow & OCR Dashboard
- BottleGrid: Implement blurred backdrop effect for bottle cards - Cascade OCR: TextDetector → RegEx → Fuzzy Match → window.ai pipeline - Smart Scan: Native OCR for Android, Live Text fallback for iOS - OCR Dashboard: Admin page at /admin/ocr-logs with stats and scan history - Features: Add feature flags in src/config/features.ts - SQL: Add ocr_logs table migration - Services: Update analyze-bottle to use OpenRouter, add save-ocr-log
This commit is contained in:
@@ -36,10 +36,10 @@ export default function EditBottleForm({ bottle, onComplete }: EditBottleFormPro
|
||||
name: bottle.name,
|
||||
distillery: bottle.distillery || '',
|
||||
category: bottle.category || '',
|
||||
abv: bottle.abv || 0,
|
||||
age: bottle.age || 0,
|
||||
abv: bottle.abv?.toString() || '',
|
||||
age: bottle.age?.toString() || '',
|
||||
whiskybase_id: bottle.whiskybase_id || '',
|
||||
purchase_price: bottle.purchase_price || '',
|
||||
purchase_price: bottle.purchase_price?.toString() || '',
|
||||
distilled_at: bottle.distilled_at || '',
|
||||
bottled_at: bottle.bottled_at || '',
|
||||
batch_info: bottle.batch_info || '',
|
||||
@@ -54,8 +54,8 @@ export default function EditBottleForm({ bottle, onComplete }: EditBottleFormPro
|
||||
const result = await discoverWhiskybaseId({
|
||||
name: formData.name,
|
||||
distillery: formData.distillery,
|
||||
abv: formData.abv,
|
||||
age: formData.age,
|
||||
abv: formData.abv ? parseFloat(formData.abv) : undefined,
|
||||
age: formData.age ? parseInt(formData.age) : undefined,
|
||||
distilled_at: formData.distilled_at || undefined,
|
||||
bottled_at: formData.bottled_at || undefined,
|
||||
batch_info: formData.batch_info || undefined,
|
||||
@@ -83,14 +83,14 @@ export default function EditBottleForm({ bottle, onComplete }: EditBottleFormPro
|
||||
try {
|
||||
const response = await updateBottle(bottle.id, {
|
||||
...formData,
|
||||
abv: Number(formData.abv),
|
||||
age: formData.age ? Number(formData.age) : undefined,
|
||||
purchase_price: formData.purchase_price ? Number(formData.purchase_price) : undefined,
|
||||
abv: formData.abv ? parseFloat(formData.abv.replace(',', '.')) : null,
|
||||
age: formData.age ? parseInt(formData.age) : null,
|
||||
purchase_price: formData.purchase_price ? parseFloat(formData.purchase_price.replace(',', '.')) : null,
|
||||
distilled_at: formData.distilled_at || undefined,
|
||||
bottled_at: formData.bottled_at || undefined,
|
||||
batch_info: formData.batch_info || undefined,
|
||||
cask_type: formData.cask_type || undefined,
|
||||
});
|
||||
} as any);
|
||||
|
||||
if (response.success) {
|
||||
setIsEditing(false);
|
||||
@@ -145,22 +145,23 @@ export default function EditBottleForm({ bottle, onComplete }: EditBottleFormPro
|
||||
<div className="space-y-2">
|
||||
<label className="text-[10px] font-black uppercase text-zinc-500 ml-1 tracking-widest">{t('bottle.abvLabel')}</label>
|
||||
<input
|
||||
type="number"
|
||||
type="text"
|
||||
inputMode="decimal"
|
||||
step="0.1"
|
||||
value={formData.abv}
|
||||
onChange={(e) => setFormData({ ...formData, abv: parseFloat(e.target.value) })}
|
||||
onChange={(e) => setFormData({ ...formData, abv: e.target.value })}
|
||||
className="w-full px-5 py-4 bg-black/40 border border-white/5 rounded-2xl outline-none focus:ring-2 focus:ring-orange-600/50 text-orange-500 text-sm font-bold transition-all"
|
||||
placeholder="e.g. 46.3"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<label className="text-[10px] font-black uppercase text-zinc-500 ml-1 tracking-widest">{t('bottle.ageLabel')}</label>
|
||||
<input
|
||||
type="number"
|
||||
type="text"
|
||||
inputMode="numeric"
|
||||
value={formData.age}
|
||||
onChange={(e) => setFormData({ ...formData, age: parseInt(e.target.value) })}
|
||||
onChange={(e) => setFormData({ ...formData, age: e.target.value })}
|
||||
className="w-full px-5 py-4 bg-black/40 border border-white/5 rounded-2xl outline-none focus:ring-2 focus:ring-orange-600/50 text-zinc-100 text-sm font-bold transition-all"
|
||||
placeholder="e.g. 12"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -196,9 +197,8 @@ export default function EditBottleForm({ bottle, onComplete }: EditBottleFormPro
|
||||
<div className="space-y-2">
|
||||
<label className="text-[10px] font-black uppercase text-zinc-500 ml-1 tracking-widest">{t('bottle.priceLabel')} (€)</label>
|
||||
<input
|
||||
type="number"
|
||||
type="text"
|
||||
inputMode="decimal"
|
||||
step="0.01"
|
||||
placeholder="0.00"
|
||||
value={formData.purchase_price}
|
||||
onChange={(e) => setFormData({ ...formData, purchase_price: e.target.value })}
|
||||
|
||||
Reference in New Issue
Block a user