Skip to content

Commit

Permalink
feat(product detail): new basic Product detail page (#55)
Browse files Browse the repository at this point in the history
* New api getProductById

* New page Product detail

* Improve PriceCard to work as ProductCard

* On PriceCard product click, go to ProductDetail page
  • Loading branch information
raphodn authored Dec 23, 2023
1 parent 74686a1 commit b435610
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 14 deletions.
30 changes: 17 additions & 13 deletions src/components/PriceCard.vue
Original file line number Diff line number Diff line change
@@ -1,27 +1,28 @@
<template>
<v-card>
<v-card-item>
<v-card-item v-if="product" @click="goToProduct(product.id)">
<template v-slot:prepend>
<v-avatar rounded="0">
<v-img v-if="price.product && price.product.image_url" :src="price.product.image_url"></v-img>
<v-img v-if="!price.product || !price.product.image_url" :src="defaultAvatar" style="filter:invert(.9);"></v-img>
<v-img v-if="product && product.image_url" :src="product.image_url"></v-img>
<v-img v-if="!product || !product.image_url" :src="defaultAvatar" style="filter:invert(.9);"></v-img>
</v-avatar>
</template>

<v-card-title v-if="price.product && price.product.product_name">{{ price.product.product_name }}</v-card-title>
<v-card-title v-if="!price.product || !price.product.product_name">{{ price.product_code }}</v-card-title>
<v-card-title>{{ product.product_name || price.product_code }}</v-card-title>

<v-card-subtitle v-if="price.product">
<span v-if="price.product.brands">{{ price.product.brands }}</span>
<span v-if="price.product.brands && price.product.product_quantity"> · </span>
<span v-if="price.product.product_quantity">{{ price.product.product_quantity }} g</span>
<v-card-subtitle>
<span v-if="product.brands">{{ product.brands }}</span>
<span v-if="product.brands && product.product_quantity"> · </span>
<span v-if="product.product_quantity">{{ product.product_quantity }} g</span>
<span v-if="!price && (product.brands || product.product_quantity)"> · </span>
<span v-if="!price">{{ product.code }}</span>
</v-card-subtitle>
<v-card-subtitle v-if="!price.product"></v-card-subtitle>
<v-card-subtitle v-if="!product"></v-card-subtitle>
</v-card-item>

<v-card-text>
<v-card-text v-if="price">
<span>{{ getPriceValueDisplay(price.price, price.currency) }}</span>
<span v-if="price.product && price.product.product_quantity"> ({{ getPricePerKilo(price.price, price.currency, price.product.product_quantity) }})</span>
<span v-if="product && product.product_quantity"> ({{ getPricePerKilo(price.price, price.currency, product.product_quantity) }})</span>
<span> · </span>
<span v-if="price.location">{{ price.location.osm_name }}, {{ price.location.osm_address_city }}</span>
<span v-if="!price.location">{{ price.location_id }}</span>
Expand All @@ -33,7 +34,7 @@

<script>
export default {
props: ['price'],
props: ['price', 'product'],
data() {
return {
defaultAvatar: 'https://world.openfoodfacts.org/images/icons/dist/packaging.svg'
Expand All @@ -51,6 +52,9 @@ export default {
getPricePerKilo(priceValue, priceCurrency, productQuantity) {
let pricePerKilo = (priceValue / productQuantity) * 1000
return `${this.getPriceValueDisplay(pricePerKilo, priceCurrency)} / kg`
},
goToProduct(productId) {
this.$router.push({ path: `/products/${productId}` })
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import SignIn from './views/SignIn.vue'
import AddPriceHome from './views/AddPriceHome.vue'
import AddPriceSingle from './views/AddPriceSingle.vue'
import PriceList from './views/PriceList.vue'
import ProductDetail from './views/ProductDetail.vue'
import Stats from './views/Stats.vue'
import NotFound from './views/NotFound.vue'

Expand All @@ -13,6 +14,7 @@ export let routes = [
{ path: '/add', name: 'add-price', component: AddPriceHome, meta: { title: 'Add a price', icon: 'mdi-plus', drawerMenu: true, requiresAuth: true }},
{ path: '/add/single', name: 'add-price-single', component: AddPriceSingle, meta: { title: 'Add a single price', requiresAuth: true }},
{ path: '/prices', name: 'prices', component: PriceList, meta: { title: 'Last prices', icon: 'mdi-tag-multiple-outline', drawerMenu: true }},
{ path: '/products/:id', name: 'product-detail', component: ProductDetail, meta: { title: 'Product detail' }},
{ path: '/stats', name: 'stats', component: Stats, meta: { title: 'Stats' }},
{ path: '/:path(.*)', component: NotFound },
]
12 changes: 12 additions & 0 deletions src/services/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,18 @@ export default {
.then((response) => response.json())
},

getProductById(productId) {
const url = `${import.meta.env.VITE_OPEN_PRICES_API_URL}/products/${productId}`
return fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.getToken()}`
},
})
.then((response) => response.json())
},

openstreetmapNominatimSearch(q) {
return fetch(`https://nominatim.openstreetmap.org/search?q=${q}&format=json&limit=5`, {
method: 'GET',
Expand Down
2 changes: 1 addition & 1 deletion src/views/PriceList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<v-row>
<v-col cols="12" sm="6" md="4" v-for="price in prices" :key="price">
<PriceCard :price="price" elevation="1" height="100%"></PriceCard>
<PriceCard :price="price" :product="price.product" elevation="1" height="100%"></PriceCard>
</v-col>
</v-row>
</template>
Expand Down
60 changes: 60 additions & 0 deletions src/views/ProductDetail.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<template>
<h1 class="mb-1">
{{ product ? product.product_name : '' }}
<v-progress-circular v-if="loading" indeterminate :size="30"></v-progress-circular>
</h1>

<PriceCard v-if="product" :product="product" elevation="1"></PriceCard>

<br />

<h2 class="mb-1">Last prices</h2>

<v-row>
<v-col cols="12" sm="6" md="4" v-for="price in productPriceList" :key="price">
<PriceCard :price="price" elevation="1" height="100%"></PriceCard>
</v-col>
</v-row>
</template>

<script>
import api from '../services/api'
import PriceCard from '../components/PriceCard.vue'
export default {
components: {
PriceCard,
},
data() {
return {
product: null,
productPriceList: [],
productPriceCount: null,
loading: false,
}
},
mounted() {
this.getProduct(),
this.getProductPrices()
},
methods: {
getProduct() {
this.loading = true
return api.getProductById(this.$route.params.id)
.then((data) => {
this.product = data
this.loading = false
})
},
getProductPrices() {
this.loading = true
return api.getPrices({ product_id: this.$route.params.id, order_by: '-created' })
.then((data) => {
this.productPriceList = data.items
this.productPriceCount = data.total
this.loading = false
})
}
}
}
</script>

0 comments on commit b435610

Please sign in to comment.