Fixes: 1) Replace deprecated context usage in `useAvatarUpload` mutation; 2) Resolve incorrect locale parsing in `useDate` utility and fix non-reactive cart state in `profile/cart.vue`; 3) Update stale imports and standardize type naming across composables; Extra: 1) Refactor i18n strings including order status and search-related texts; 2) Replace temporary workarounds with `apollo-upload-client` configuration and add `apollo-upload-link.ts` plugin; 3) Cleanup redundant files, comments, and improve SCSS structure with new variables and placeholders.
246 lines
No EOL
5.3 KiB
Vue
246 lines
No EOL
5.3 KiB
Vue
<template>
|
|
<el-collapse-item
|
|
class="order"
|
|
>
|
|
<template #title="{ isActive }">
|
|
<div :class="['order__top', { 'is-active': isActive }]">
|
|
<div>
|
|
<p>{{ t('profile.orders.id') }}: {{ order.humanReadableId }}</p>
|
|
<p v-if="order.buyTime">{{ useDate(order.buyTime, locale) }}</p>
|
|
<el-tooltip
|
|
:content="order.status"
|
|
placement="top"
|
|
>
|
|
<p class="status" :style="[{ backgroundColor: statusColor(order.status) }]">
|
|
{{ order.status }}
|
|
<icon name="material-symbols:info-outline-rounded" size="14" />
|
|
</p>
|
|
</el-tooltip>
|
|
</div>
|
|
<icon
|
|
name="material-symbols:keyboard-arrow-down"
|
|
size="22"
|
|
class="order__top-icon"
|
|
:class="[{ active: isActive }]"
|
|
/>
|
|
</div>
|
|
<div class="order__top-bottom" :class="{ active: !isActive }">
|
|
<div>
|
|
<div>
|
|
<div>
|
|
<nuxt-img
|
|
v-for="product in order.orderProducts.edges"
|
|
:key="product.node.uuid"
|
|
:src="product.node.product.images.edges[0].node.image"
|
|
:alt="product.node.product.name"
|
|
format="webp"
|
|
densities="x1"
|
|
/>
|
|
</div>
|
|
<p>{{ order.totalPrice }}{{ CURRENCY }}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
<div class="order__main">
|
|
<div
|
|
class="order__product"
|
|
v-for="product in order.orderProducts.edges"
|
|
:key="product.node.uuid"
|
|
>
|
|
<div class="order__product-left">
|
|
<nuxt-img
|
|
:src="product.node.product.images.edges[0].node.image"
|
|
:alt="product.node.product.name"
|
|
/>
|
|
<p>{{ product.node.product.name }}</p>
|
|
</div>
|
|
<div class="order__product-right">
|
|
<h6>{{ t('profile.orders.price') }}: {{ product.node.product.price * product.node.quantity }}{{ CURRENCY }}</h6>
|
|
<p>{{ product.node.quantity }} X {{ product.node.product.price }}{{ CURRENCY }}</p>
|
|
</div>
|
|
</div>
|
|
<div class="order__total">
|
|
<p>{{ t('profile.orders.total') }}: {{ order.totalPrice }}{{ CURRENCY }}</p>
|
|
</div>
|
|
</div>
|
|
</el-collapse-item>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import {useDate} from "~/composables/date";
|
|
import {CURRENCY, orderStatuses} from "~/config/constants";
|
|
import type {IOrder} from "~/types";
|
|
|
|
const props = defineProps<{
|
|
order: IOrder;
|
|
}>();
|
|
|
|
const {t, locale} = useI18n();
|
|
|
|
const statusColor = (status: string) => {
|
|
switch (status) {
|
|
case orderStatuses.FAILED:
|
|
return '#FF0000';
|
|
|
|
case orderStatuses.PAYMENT:
|
|
return '#FFC107';
|
|
|
|
case orderStatuses.CREATED:
|
|
return '#007BFF';
|
|
|
|
case orderStatuses.DELIVERING:
|
|
return '#00C853';
|
|
|
|
case orderStatuses.FINISHED:
|
|
return '#00C853';
|
|
|
|
case orderStatuses.MOMENTAL:
|
|
return '#00C853';
|
|
|
|
default:
|
|
return '#000';
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style scoped lang="scss">
|
|
.order {
|
|
&__top {
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: space-between;
|
|
gap: 20px;
|
|
padding: 0 10px 5px 10px;
|
|
|
|
& div {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 25px;
|
|
|
|
& p {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 5px;
|
|
|
|
&.status {
|
|
border-radius: $default_border_radius;
|
|
padding: 3px 7px;
|
|
}
|
|
}
|
|
}
|
|
|
|
&-icon {
|
|
transition: 0.2s;
|
|
|
|
&.active {
|
|
transform: rotate(-180deg);
|
|
}
|
|
}
|
|
|
|
&-bottom {
|
|
display: grid;
|
|
grid-template-rows: 0fr;
|
|
transition: grid-template-rows 0.2s ease;
|
|
overflow: hidden;
|
|
|
|
&.active {
|
|
grid-template-rows: 1fr;
|
|
}
|
|
|
|
& > * {
|
|
min-height: 0;
|
|
}
|
|
|
|
& div {
|
|
& div {
|
|
padding-top: 10px;
|
|
border-top: 1px solid $accent;
|
|
display: flex;
|
|
align-items: flex-start;
|
|
justify-content: space-between;
|
|
gap: 25px;
|
|
|
|
& div {
|
|
padding-top: 0;
|
|
border: none;
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 10px;
|
|
|
|
& img {
|
|
height: 65px;
|
|
border-radius: $default_border_radius;
|
|
}
|
|
}
|
|
|
|
& p {
|
|
font-weight: 600;
|
|
font-size: 20px;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
&__main {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 20px;
|
|
}
|
|
|
|
&__product {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
justify-content: space-between;
|
|
padding-bottom: 15px;
|
|
border-bottom: 2px solid $accent;
|
|
|
|
&-left {
|
|
display: flex;
|
|
align-items: flex-start;
|
|
gap: 10px;
|
|
|
|
& img {
|
|
height: 150px;
|
|
border-radius: $default_border_radius;
|
|
}
|
|
|
|
& p {
|
|
font-size: 18px;
|
|
font-weight: 500;
|
|
}
|
|
}
|
|
|
|
&-right {
|
|
display: flex;
|
|
flex-direction: column;
|
|
align-items: flex-end;
|
|
|
|
& h6 {
|
|
font-size: 20px;
|
|
}
|
|
|
|
& p {
|
|
font-size: 14px;
|
|
}
|
|
}
|
|
}
|
|
|
|
&__total {
|
|
display: flex;
|
|
align-items: flex-end;
|
|
justify-content: flex-end;
|
|
|
|
& p {
|
|
font-size: 20px;
|
|
font-weight: 600;
|
|
}
|
|
}
|
|
}
|
|
|
|
:deep(.el-collapse-item__header) {
|
|
height: fit-content;
|
|
padding-block: 10px;
|
|
}
|
|
</style> |