feat: 5-tier pricing UI, market ticker, delivery map, and stats dashboard
Full frontend companion to the API updates: - Pricing: Oil price admin page now supports 5-tier configuration for same-day/prime/emergency fees with collapsible tier sections - Market Ticker: Add GlobalMarketTicker and OilPriceTicker components with real-time commodity + competitor prices in header bar - Delivery Map: New interactive Leaflet map view for daily deliveries - Stats: Add PricingHistoryChart component and info pages for market trends with daily/weekly/monthly gallon charts and YoY comparisons - Layout: Refactor header navbar to separate search into navbar-center, add oilPrice Pinia store with polling, update sidebar navigation - Forms: Wire tier selection into delivery create/edit flows, update types and services for new pricing and scraper API endpoints Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,9 +1,9 @@
|
||||
<!-- src/pages/customer/profile/profile.vue -->
|
||||
<template>
|
||||
<div class="w-full min-h-screen bg-base-200 px-4 md:px-10">
|
||||
<div class="w-full min-h-screen px-4 md:px-10">
|
||||
<!-- ... breadcrumbs ... -->
|
||||
|
||||
<div v-if="customer && customer.id" class="bg-neutral rounded-lg p-4 sm:p-6 mt-6">
|
||||
<div v-if="customer && customer.id" class="mt-6">
|
||||
|
||||
<!-- Current Plan Status Banner - Same as ServicePlanEdit.vue -->
|
||||
<div v-if="servicePlan && servicePlan.contract_plan > 0" class="alert alert-info mb-6"
|
||||
@@ -40,12 +40,15 @@
|
||||
class="xl:col-span-7" :customer="customer" />
|
||||
|
||||
<!-- You can add a placeholder for when the map isn't ready -->
|
||||
<div v-else class="xl:col-span-7 bg-base-100 rounded-lg flex justify-center items-center">
|
||||
<div v-else class="xl:col-span-7 card-glass flex justify-center items-center">
|
||||
<p class="text-gray-400">Location not available...</p>
|
||||
</div>
|
||||
|
||||
<ProfileSummary class="xl:col-span-5" :customer="customer" :automatic_status="automatic_status"
|
||||
:customer_description="customer_description.description" @toggle-automatic="userAutomatic" />
|
||||
<div class="xl:col-span-5 space-y-6">
|
||||
<ProfileSummary :customer="customer" :automatic_status="automatic_status"
|
||||
:customer_description="customer_description.description" @toggle-automatic="userAutomatic" />
|
||||
<CustomerStats :stats="customer_stats" :last_delivery="customer_last_delivery" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<HistoryTabs :deliveries="deliveries" :autodeliveries="autodeliveries" :service-calls="serviceCalls"
|
||||
@@ -57,7 +60,7 @@
|
||||
<!-- FIX: Changed `lg:` to `xl:` -->
|
||||
<div class="xl:col-span-4 space-y-6">
|
||||
<!-- Authorize.net Account Status Box -->
|
||||
<div v-if="customer.id" class="bg-base-100 rounded-lg p-4 border">
|
||||
<div v-if="customer.id" class="card-glass p-4">
|
||||
<div class="flex flex-col lg:flex-row lg:items-center lg:justify-between">
|
||||
<div class="flex items-center gap-3 mb-3 md:mb-0">
|
||||
<svg class="w-5 h-5 text-blue-600" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
@@ -101,14 +104,14 @@
|
||||
<TankEstimation :customer-id="customer.id" />
|
||||
|
||||
<CustomerComments :comments="comments" @add-comment="onSubmitSocial" @delete-comment="deleteCustomerSocial" />
|
||||
<CustomerStats :stats="customer_stats" :last_delivery="customer_last_delivery" />
|
||||
<TankInfo :customer_id="customer.id" :tank="customer_tank" :description="customer_description" />
|
||||
|
||||
<TankInfo :customer_id="customer.id" :tank="customer_tank" :description="customer_description" :estimation="autoEstimation" />
|
||||
<EquipmentParts :parts="currentParts" @open-parts-modal="openPartsModal" />
|
||||
<CreditCards :cards="credit_cards" :count="credit_cards_count" :user_id="customer.id"
|
||||
:auth_net_profile_id="customer.auth_net_profile_id" @edit-card="editCard" @remove-card="removeCard" />
|
||||
|
||||
<!-- Automatic Delivery Actions Box -->
|
||||
<div v-if="automatic_status === 1 && autodeliveries.length > 0" class="bg-base-100 rounded-lg p-4 border">
|
||||
<div v-if="automatic_status === 1 && autodeliveries.length > 0" class="card-glass p-4">
|
||||
<h3 class="font-semibold mb-4">Automatic Delivery Actions</h3>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<router-link v-if="autodeliveries[0].auto_status != 3"
|
||||
@@ -354,6 +357,7 @@ const autodeliveries = ref([] as AutomaticDelivery[])
|
||||
const serviceCalls = ref([] as ServiceCall[])
|
||||
const transactions = ref([] as AuthorizeTransaction[])
|
||||
// --- END OF UPDATES ---
|
||||
const autoEstimation = ref<{ confidence_score: number; k_factor_source: string; days_remaining: number } | undefined>(undefined)
|
||||
const automatic_response = ref(0)
|
||||
const credit_cards_count = ref(0)
|
||||
const customer = ref({ id: 0, user_id: null as number | null, customer_first_name: '', customer_last_name: '', customer_town: '', customer_address: '', customer_state: 0, customer_zip: '', customer_apt: '', customer_home_type: 0, customer_phone_number: '', customer_latitude: 0, customer_longitude: 0, correct_address: true, account_number: '', auth_net_profile_id: null })
|
||||
@@ -555,6 +559,18 @@ const getCustomerAutoDelivery = (userid: number) => {
|
||||
deliveryService.auto.getProfileDeliveries(userid).then((response: AxiosResponse<any>) => {
|
||||
autodeliveries.value = response.data || []
|
||||
})
|
||||
// Also fetch the auto delivery record for estimation data
|
||||
deliveryService.auto.getByCustomer(userid).then((response: AxiosResponse<any>) => {
|
||||
if (response.data && response.data.id) {
|
||||
autoEstimation.value = {
|
||||
confidence_score: response.data.confidence_score ?? 20,
|
||||
k_factor_source: response.data.k_factor_source ?? 'default',
|
||||
days_remaining: response.data.days_remaining ?? 999
|
||||
}
|
||||
}
|
||||
}).catch(() => {
|
||||
autoEstimation.value = undefined
|
||||
})
|
||||
}
|
||||
|
||||
const getCustomerDelivery = (userid: number, delivery_page: number) => {
|
||||
@@ -1026,3 +1042,9 @@ const getAccountStatusMessage = (): string => {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.card-glass {
|
||||
@apply bg-gradient-to-br from-neutral/90 to-neutral/70 backdrop-blur-sm rounded-xl shadow-lg border border-base-content/5;
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user