Skip to content

Commit

Permalink
feat(price card): improve look & feel (#77)
Browse files Browse the repository at this point in the history
* Add row & cols

* Move info below. Relative date display

* Improve display in other pages (location, product & user detail pages)

* Add link to user
  • Loading branch information
raphodn committed Dec 29, 2023
1 parent 021a655 commit 3151439
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 39 deletions.
81 changes: 56 additions & 25 deletions src/components/PriceCard.vue
Original file line number Diff line number Diff line change
@@ -1,37 +1,53 @@
<template>
<v-card>
<v-card-item @click="goToProduct()">
<template v-slot:prepend>
<v-avatar rounded="0">
<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-container class="pa-2">
<v-row>
<v-col v-if="!hideProductImage" style="max-width:25%">
<v-img v-if="product && product.image_url" :src="product.image_url" style="max-height:100px;width:100px"></v-img>
<v-img v-if="!product || !product.image_url" :src="defaultAvatar" style="height:100px;width:100px;filter:invert(.9);"></v-img>
</v-col>
<v-col style="max-width:75%">
<h3 v-if="!hideProductInfo" @click="goToProduct()">{{ getPriceProductTitle() }}</h3>

<v-card-title>{{ getPriceProductTitle() }}</v-card-title>
<p v-if="!hideProductInfo" class="mb-2">
<span v-if="hasProductBrands">
<v-chip label size="small" density="comfortable" class="mr-1">{{ product.brands }}</v-chip>
</span>
<span v-if="hasProductQuantity">
<v-chip label size="small" density="comfortable" class="mr-1">{{ product.product_quantity }} g</v-chip>
</span>
<span v-if="!price">
<v-chip label size="small" density="comfortable" class="mr-1">{{ product.code }}</v-chip>
</span>
</p>

<v-card-subtitle>
<span v-if="hasProductBrands">{{ product.brands }}</span>
<span v-if="hasProductBrands && hasProductQuantity"> · </span>
<span v-if="hasProductQuantity">{{ 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="!product"></v-card-subtitle>
</v-card-item>
<v-sheet v-if="price">
<p class="mb-2">
<span>{{ getPriceValueDisplay() }}</span>
<span v-if="hasProductQuantity"> ({{ getPricePerKilo() }})</span>
<span> on <i>{{ getDateFormatted(price.date) }}</i></span>
</p>
</v-sheet>
</v-col>
</v-row>

<v-card-text v-if="price">
<span>{{ getPriceValueDisplay() }}</span>
<span v-if="(hasProductQuantity)"> ({{ getPricePerKilo() }})</span>
<span> · </span>
<span @click="goToLocation()">{{ getPriceLocationTitle() }}</span>
<span> · </span>
<span>{{ price.date }}</span>
</v-card-text>
<div class="d-flex flex-wrap ga-1 mt-2" v-if="price">
<v-chip v-if="!hidePriceLocation" class="mr-1" label size="small" prepend-icon="mdi-map-marker-outline" @click="goToLocation()">
{{ getPriceLocationTitle() }}
</v-chip>
<v-chip class="mr-1" label size="small" prepend-icon="mdi-account" @click="goToUser()">
{{ price.owner }}
</v-chip>
<v-chip label size="small" prepend-icon="mdi-clock-outline">
{{ getRelativeDateTimeFormatted(price.created) }}
</v-chip>
</div>
</v-container>
</v-card>
</template>

<script>
import utils from '../utils.js'
// Import category tags static JSON file
import CategoryTags from '../data/category-tags.json'
Expand All @@ -46,6 +62,9 @@ export default {
props: {
'price': null,
'product': null,
'hideProductImage': false,
'hideProductInfo': false,
'hidePriceLocation': false,
'readonly': false
},
data() {
Expand Down Expand Up @@ -115,6 +134,12 @@ export default {
}
return this.price.location_id
},
getDateFormatted(dateString) {
return utils.prettyDate(dateString)
},
getRelativeDateTimeFormatted(dateTimeString) {
return utils.prettyRelativeDateTime(dateTimeString, true)
},
goToProduct() {
if (this.readonly || !this.hasProduct) {
return
Expand All @@ -127,6 +152,12 @@ export default {
}
this.$router.push({ path: `/locations/${this.price.location_id}` })
},
goToUser() {
if (this.readonly) {
return
}
this.$router.push({ path: `/users/${this.price.owner}` })
},
getCategoryName(categoryTag) {
return CategoryTagsByIndex[categoryTag].name
}
Expand Down
32 changes: 32 additions & 0 deletions src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,38 @@ function addObjectToArray(arr, obj, unshift = false, avoidDuplicates = true) {
return arr
}

/**
* input: '2023-12-25'
* output: '12/25/2023'
*/
function prettyDate(dateString) {
const date = new Date(dateString)
return new Intl.DateTimeFormat('default').format(date)
}

/**
* https://johnresig.com/blog/javascript-pretty-date/
* input: '2023-12-27T17:08:19.021410+01:00'
* output: '5 hours ago', 'Yesterday', '2 days ago'...
*/
function prettyRelativeDateTime(dateTimeString, short=false) {
var date = new Date((dateTimeString || "").replace(/-/g, "/").replace(/[TZ]/g, " ")),
diff = (((new Date()).getTime() - date.getTime()) / 1000),
day_diff = Math.floor(diff / 86400);

if (isNaN(day_diff) || day_diff < 0 || day_diff >= 31) return;

if (short) {
// replace 'days' with 'd', remove 'Yesterday'
return day_diff == 0 && (
diff < 60 && "just now" || diff < 120 && "1m ago" || diff < 3600 && Math.floor(diff / 60) + "m ago" || diff < 7200 && "1h ago" || diff < 86400 && Math.floor(diff / 3600) + "h ago") || day_diff < 7 && day_diff + "d ago" || day_diff < 31 && Math.ceil(day_diff / 7) + "w ago";
}
return day_diff == 0 && (
diff < 60 && "just now" || diff < 120 && "1 minute ago" || diff < 3600 && Math.floor(diff / 60) + " minutes ago" || diff < 7200 && "1 hour ago" || diff < 86400 && Math.floor(diff / 3600) + " hours ago") || day_diff == 1 && "Yesterday" || day_diff < 7 && day_diff + " days ago" || day_diff < 31 && Math.ceil(day_diff / 7) + " weeks ago";
}

export default {
addObjectToArray,
prettyDate,
prettyRelativeDateTime,
}
10 changes: 3 additions & 7 deletions src/views/LocationDetail.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,10 @@
<template>
<h1 class="mb-1">
{{ location ? location.location_name : '' }}
<v-progress-circular v-if="loading" indeterminate :size="30"></v-progress-circular>
</h1>

<v-row>
<v-col cols="12" sm="6">
<v-card
:title="getLocationTitle(location)"
:subtitle="location ? location.osm_display_name : ''"
:prepend-icon="location ? 'mdi-map-marker' : 'mdi-map-marker-remove-variant'">
:prepend-icon="location ? 'mdi-map-marker-outline' : 'mdi-map-marker-remove-variant'">
</v-card>
</v-col>
</v-row>
Expand All @@ -30,11 +25,12 @@
<h2 class="mb-1">
Latest prices
<small>{{ locationPriceCount }}</small>
<v-progress-circular v-if="loading" indeterminate :size="30"></v-progress-circular>
</h2>

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

<v-row>
<v-col cols="12" sm="6">
<PriceCard v-if="product" :product="product" elevation="1"></PriceCard>
<PriceCard v-if="product" :product="product" :readonly="true" elevation="1"></PriceCard>
</v-col>
</v-row>

Expand All @@ -26,11 +21,12 @@
<h2 class="mb-1">
Latest prices
<small>{{ productPriceCount }}</small>
<v-progress-circular v-if="loading" indeterminate :size="30"></v-progress-circular>
</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>
<PriceCard :price="price" :product="product" :hideProductImage="true" :hideProductInfo="true" elevation="1" height="100%"></PriceCard>
</v-col>
</v-row>
</template>
Expand Down
1 change: 1 addition & 0 deletions src/views/UserDetail.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<h2 class="mb-1">
Latest prices
<small>{{ userPriceCount }}</small>
<v-progress-circular v-if="loading" indeterminate :size="30"></v-progress-circular>
</h2>

<v-row>
Expand Down

0 comments on commit 3151439

Please sign in to comment.