Compare commits
2 Commits
feature/is
...
feature/is
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d35a3e7b3 | ||
| 670b2f9200 |
@@ -131,6 +131,16 @@ const { addInventoryItem, addItemTags } = useInventory()
|
||||
const { getUnits } = useUnits()
|
||||
const { getTags } = useTags()
|
||||
|
||||
const props = defineProps<{
|
||||
initialData?: {
|
||||
barcode?: string
|
||||
name?: string
|
||||
brand?: string
|
||||
image_url?: string
|
||||
quantity?: string
|
||||
}
|
||||
}>()
|
||||
|
||||
const emit = defineEmits<{
|
||||
close: []
|
||||
added: [item: any]
|
||||
@@ -166,6 +176,40 @@ onMounted(async () => {
|
||||
if (defaultUnit) {
|
||||
form.unit_id = defaultUnit.id
|
||||
}
|
||||
|
||||
// Pre-fill from initial data (scan-to-add flow)
|
||||
if (props.initialData) {
|
||||
if (props.initialData.name) {
|
||||
form.name = props.initialData.name
|
||||
}
|
||||
|
||||
// Add brand to notes if available
|
||||
if (props.initialData.brand) {
|
||||
form.notes = `Brand: ${props.initialData.brand}`
|
||||
|
||||
if (props.initialData.barcode) {
|
||||
form.notes += `\nBarcode: ${props.initialData.barcode}`
|
||||
}
|
||||
} else if (props.initialData.barcode) {
|
||||
form.notes = `Barcode: ${props.initialData.barcode}`
|
||||
}
|
||||
|
||||
// Parse quantity if available (e.g., "750g")
|
||||
if (props.initialData.quantity) {
|
||||
const quantityMatch = props.initialData.quantity.match(/^([\d.]+)\s*([a-zA-Z]+)$/)
|
||||
if (quantityMatch) {
|
||||
form.quantity = parseFloat(quantityMatch[1])
|
||||
// Try to match unit
|
||||
const unitAbbr = quantityMatch[2].toLowerCase()
|
||||
const matchedUnit = units.value.find(u =>
|
||||
u.abbreviation.toLowerCase() === unitAbbr
|
||||
)
|
||||
if (matchedUnit) {
|
||||
form.unit_id = matchedUnit.id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Unit options for select
|
||||
|
||||
61
app/composables/useProductLookup.ts
Normal file
61
app/composables/useProductLookup.ts
Normal file
@@ -0,0 +1,61 @@
|
||||
// Composable for product lookup via Edge Function
|
||||
|
||||
export interface ProductData {
|
||||
barcode: string
|
||||
name: string
|
||||
brand?: string
|
||||
quantity?: string
|
||||
image_url?: string
|
||||
category?: string
|
||||
cached?: boolean
|
||||
}
|
||||
|
||||
export const useProductLookup = () => {
|
||||
const supabase = useSupabaseClient()
|
||||
const isLoading = ref(false)
|
||||
const error = ref<string | null>(null)
|
||||
|
||||
const lookupProduct = async (barcode: string): Promise<ProductData | null> => {
|
||||
isLoading.value = true
|
||||
error.value = null
|
||||
|
||||
try {
|
||||
const { data, error: functionError } = await supabase.functions.invoke('product-lookup', {
|
||||
body: { barcode }
|
||||
})
|
||||
|
||||
if (functionError) {
|
||||
console.error('Product lookup error:', functionError)
|
||||
error.value = functionError.message || 'Failed to lookup product'
|
||||
|
||||
// Return basic product data even on error
|
||||
return {
|
||||
barcode,
|
||||
name: `Product ${barcode}`,
|
||||
cached: false
|
||||
}
|
||||
}
|
||||
|
||||
return data as ProductData
|
||||
|
||||
} catch (err) {
|
||||
console.error('Unexpected error during product lookup:', err)
|
||||
error.value = err instanceof Error ? err.message : 'Unknown error'
|
||||
|
||||
// Return basic product data even on error
|
||||
return {
|
||||
barcode,
|
||||
name: `Product ${barcode}`,
|
||||
cached: false
|
||||
}
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
lookupProduct,
|
||||
isLoading: readonly(isLoading),
|
||||
error: readonly(error)
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,8 @@
|
||||
<div v-if="showAddForm" class="fixed inset-0 z-50 flex items-start justify-center pt-20 px-4 bg-black/50">
|
||||
<div class="w-full max-w-lg">
|
||||
<AddItemForm
|
||||
@close="showAddForm = false"
|
||||
:initial-data="prefilledData"
|
||||
@close="handleCloseAddForm"
|
||||
@added="handleItemAdded"
|
||||
/>
|
||||
</div>
|
||||
@@ -56,13 +57,42 @@ definePageMeta({
|
||||
layout: 'default'
|
||||
})
|
||||
|
||||
const route = useRoute()
|
||||
const router = useRouter()
|
||||
|
||||
const showAddForm = ref(false)
|
||||
const editingItem = ref<any>(null)
|
||||
const refreshKey = ref(0)
|
||||
const inventoryListRef = ref()
|
||||
const prefilledData = ref<any>(null)
|
||||
|
||||
// Handle scan-to-add flow (Issue #25)
|
||||
onMounted(() => {
|
||||
if (route.query.action === 'add') {
|
||||
// Pre-fill data from query params (from scan)
|
||||
prefilledData.value = {
|
||||
barcode: route.query.barcode as string || undefined,
|
||||
name: route.query.name as string || undefined,
|
||||
brand: route.query.brand as string || undefined,
|
||||
image_url: route.query.image_url as string || undefined,
|
||||
quantity: route.query.quantity as string || undefined,
|
||||
}
|
||||
|
||||
showAddForm.value = true
|
||||
|
||||
// Clean up URL
|
||||
router.replace({ query: {} })
|
||||
}
|
||||
})
|
||||
|
||||
const handleCloseAddForm = () => {
|
||||
showAddForm.value = false
|
||||
prefilledData.value = null
|
||||
}
|
||||
|
||||
const handleItemAdded = (item: any) => {
|
||||
showAddForm.value = false
|
||||
prefilledData.value = null
|
||||
// Reload the inventory list
|
||||
inventoryListRef.value?.reload()
|
||||
}
|
||||
|
||||
@@ -72,49 +72,33 @@ definePageMeta({
|
||||
|
||||
const scannedBarcode = ref<string | null>(null)
|
||||
const productData = ref<any>(null)
|
||||
const isLookingUp = ref(false)
|
||||
const lookupError = ref<string | null>(null)
|
||||
const showManualEntry = ref(false)
|
||||
|
||||
// Use product lookup composable
|
||||
const { lookupProduct, isLoading: isLookingUp, error: lookupError } = useProductLookup()
|
||||
|
||||
const handleBarcodeDetected = async (barcode: string) => {
|
||||
scannedBarcode.value = barcode
|
||||
lookupError.value = null
|
||||
isLookingUp.value = true
|
||||
|
||||
try {
|
||||
// TODO: Implement product lookup via Edge Function (Issue #24)
|
||||
// For now, create a basic product object
|
||||
await new Promise(resolve => setTimeout(resolve, 1000)) // Simulate API call
|
||||
|
||||
productData.value = {
|
||||
name: `Product ${barcode}`,
|
||||
brand: 'Unknown Brand',
|
||||
barcode: barcode,
|
||||
image_url: null
|
||||
}
|
||||
|
||||
lookupError.value = 'Product lookup not yet implemented. Using default data.'
|
||||
} catch (error) {
|
||||
console.error('Product lookup error:', error)
|
||||
lookupError.value = 'Failed to look up product. You can still add it manually.'
|
||||
productData.value = {
|
||||
name: `Product ${barcode}`,
|
||||
barcode: barcode
|
||||
}
|
||||
} finally {
|
||||
isLookingUp.value = false
|
||||
|
||||
// Fetch product data from Edge Function
|
||||
const data = await lookupProduct(barcode)
|
||||
|
||||
if (data) {
|
||||
productData.value = data
|
||||
}
|
||||
}
|
||||
|
||||
const addToInventory = () => {
|
||||
// TODO: Implement scan-to-add flow (Issue #25)
|
||||
// Navigate to add form with pre-filled data
|
||||
// Navigate to home page with add form open and pre-filled
|
||||
navigateTo({
|
||||
path: '/',
|
||||
query: {
|
||||
action: 'add',
|
||||
barcode: scannedBarcode.value,
|
||||
name: productData.value?.name,
|
||||
brand: productData.value?.brand
|
||||
name: productData.value?.name || undefined,
|
||||
brand: productData.value?.brand || undefined,
|
||||
image_url: productData.value?.image_url || undefined,
|
||||
quantity: productData.value?.quantity || undefined
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user