|
|
@@ -1,15 +1,20 @@
|
|
|
import { computed, reactive, readonly, ref } from 'vue'
|
|
|
+import { storeToRefs } from 'pinia'
|
|
|
import { useApi } from '~/composables/useApi'
|
|
|
import { skillApi } from '~/api/skill'
|
|
|
+import { useAuthStore } from '~/stores/auth'
|
|
|
+import { useFirstOrderDiscountStore } from '~/stores/firstOrderDiscount'
|
|
|
|
|
|
export interface OrderPopupOptions {
|
|
|
avatar: string
|
|
|
name: string
|
|
|
productType: string
|
|
|
- /** price per unit (e.g. coins per hour) */
|
|
|
+ /** Original price per unit (e.g. coins per hour). First unit may be discounted; rest at this rate. */
|
|
|
rate: number
|
|
|
/** unit text, for example "/h" */
|
|
|
unit?: string
|
|
|
+ /** Skill owner userNo (for first-order discount: exclude own products) */
|
|
|
+ ownerUserNo?: string
|
|
|
/** minimum quantity allowed */
|
|
|
minQuantity?: number
|
|
|
/** maximum quantity allowed */
|
|
|
@@ -33,8 +38,11 @@ export interface OrderPopupState {
|
|
|
avatar: string
|
|
|
name: string
|
|
|
productType: string
|
|
|
+ /** Original unit price */
|
|
|
rate: number
|
|
|
unit: string
|
|
|
+ /** Skill owner userNo for discount eligibility */
|
|
|
+ ownerUserNo: string | null
|
|
|
quantity: number
|
|
|
minQuantity: number
|
|
|
maxQuantity?: number
|
|
|
@@ -57,6 +65,7 @@ const state = reactive<OrderPopupState>({
|
|
|
productType: '',
|
|
|
rate: 0,
|
|
|
unit: '/h',
|
|
|
+ ownerUserNo: null,
|
|
|
quantity: DEFAULT_MIN_QUANTITY,
|
|
|
minQuantity: DEFAULT_MIN_QUANTITY,
|
|
|
maxQuantity: undefined,
|
|
|
@@ -67,7 +76,25 @@ const state = reactive<OrderPopupState>({
|
|
|
})
|
|
|
const confirmHandler = ref<((orderId: string, totalPrice: number) => void) | null>(null)
|
|
|
|
|
|
-const totalPrice = computed(() => state.quantity * state.rate)
|
|
|
+// Lazy store access inside computed so Pinia is only used when composable runs in component context
|
|
|
+const firstUnitPrice = computed(() => {
|
|
|
+ const firstOrderStore = useFirstOrderDiscountStore()
|
|
|
+ const { userProfile } = storeToRefs(useAuthStore())
|
|
|
+ return firstOrderStore.getDisplayPrice(state.rate, state.ownerUserNo ?? undefined, userProfile.value?.userNo)
|
|
|
+})
|
|
|
+const hasDiscount = computed(() => {
|
|
|
+ const firstOrderStore = useFirstOrderDiscountStore()
|
|
|
+ const { userProfile } = storeToRefs(useAuthStore())
|
|
|
+ return firstOrderStore.isDiscountEligible(state.rate, state.ownerUserNo ?? undefined, userProfile.value?.userNo)
|
|
|
+})
|
|
|
+const discountAmount = computed(() =>
|
|
|
+ hasDiscount.value && state.quantity >= 1 ? state.rate - firstUnitPrice.value : 0,
|
|
|
+)
|
|
|
+const totalPrice = computed(() =>
|
|
|
+ state.quantity <= 0
|
|
|
+ ? 0
|
|
|
+ : firstUnitPrice.value + (state.quantity - 1) * state.rate,
|
|
|
+)
|
|
|
|
|
|
const clampQuantity = (value: number): number => {
|
|
|
if (state.specificQuantity != null) return state.specificQuantity
|
|
|
@@ -88,6 +115,7 @@ const open = (options: OrderPopupOptions) => {
|
|
|
state.productType = options.productType
|
|
|
state.rate = options.rate
|
|
|
state.unit = options.unit ?? '/h'
|
|
|
+ state.ownerUserNo = options.ownerUserNo ?? null
|
|
|
state.minQuantity = options.minQuantity ?? DEFAULT_MIN_QUANTITY
|
|
|
state.maxQuantity = options.maxQuantity
|
|
|
state.specificQuantity = options.specificQuantity
|
|
|
@@ -157,6 +185,10 @@ export const useOrderPopup = () => {
|
|
|
return {
|
|
|
state: readonly(state),
|
|
|
totalPrice,
|
|
|
+ firstUnitPrice,
|
|
|
+ hasDiscount,
|
|
|
+ discountAmount,
|
|
|
+ discountRatePercent: computed(() => useFirstOrderDiscountStore().discountRatePercent),
|
|
|
open,
|
|
|
close,
|
|
|
confirm,
|