Hello from MCP server
<template>
<BaseLayout title="Problem Preview">
<ion-grid :fixed="true">
<ion-row>
<ion-col>
<!-- Problem Information -->
<div class="problem-header">
<h2>{{ problem?.name || "Loading..." }}</h2>
<p class="problem-description" v-if="problem?.description">
{{ problem.description }}
</p>
</div>
<div class="divider"></div>
<!-- Linked Menus Section -->
<div class="menus-section" v-if="linkedMenus.length > 0">
<h3>Related Menus</h3>
<div class="menu-list">
<div v-for="menu in linkedMenus" :key="menu.id" class="menu-item">
<h4>{{ menu.name }}</h4>
</div>
</div>
</div>
<!-- Offers Overview -->
<div class="offers-section" v-if="relatedOffers.length > 0">
<h3>Available Offers ({{ relatedOffers.length }})</h3>
<div class="offers-grid">
<div
v-for="offer in relatedOffers"
:key="offer.id"
class="offer-card"
>
<div class="tier-badge" v-if="offer.tierName">
{{ offer.tierName }}
</div>
<div class="offer-name">{{ offer.name }}</div>
<div class="offer-subtitle" v-if="offer.tierTitle">
{{ offer.tierTitle }}
</div>
<div>Tech handbook info will go here</div>
</div>
</div>
</div>
<div v-if="relatedOffers.length === 0 && !loading" class="no-offers">
<p>No offers found for the linked menus.</p>
</div>
<div class="button-group">
<ion-button @click="confirmProblem" :disabled="!problem">
Select Problem
</ion-button>
<ion-button color="tertiary" fill="outline" @click="goToSession">
Session Home
</ion-button>
</div>
</ion-col>
</ion-row>
</ion-grid>
</BaseLayout>
</template>
<script setup lang="ts">
import { onMounted, ref } from "vue";
import { useRoute, useRouter, RouterLink } from "vue-router";
import { IonButton, IonGrid, IonRow, IonCol } from "@ionic/vue";
import BaseLayout from "@/components/BaseLayout.vue";
import { getDb } from "@/dataAccess/getDb";
import { getApi } from "@/dataAccess/getApi";
import type {
ProblemsRecord,
MenusRecord,
OffersRecord,
} from "@/pocketbase-types.ts";
import { useSessionStore } from "@/stores/session";
const route = useRoute();
const router = useRouter();
const sessionStore = useSessionStore();
const problem = ref<ProblemsRecord>();
const linkedMenus = ref<MenusRecord[]>([]);
const relatedOffers = ref<any[]>([]); // Changed to any[] to include tier data
const loading = ref(true);
const confirmProblem = async () => {
// Navigate to confirm-job with problem ID (don't create job yet)
if (problem.value) {
router.push(`/confirm-job?problemId=${problem.value.id}`);
}
};
const goToSession = () => {
router.push("/service-call");
};
onMounted(async () => {
loading.value = true;
const db = await getDb();
if (db) {
// Fetch the problem
problem.value = (await db.problems.byId(route.params.id as string)) || {};
if (problem.value && problem.value.menus) {
// Fetch linked menus with their tiers and offers
const offerSet = new Set<string>();
for (const menuId of problem.value.menus) {
// Use byMenuId to get the full menu with tiers
const menuWithTiers = await db.menus.byMenuId(menuId);
if (menuWithTiers) {
// Add to linked menus list (simplified version for display)
linkedMenus.value.push({
id: menuWithTiers.id,
name: menuWithTiers.name,
refId: menuWithTiers.refId,
org: menuWithTiers.org,
books: menuWithTiers.books,
created: menuWithTiers.created,
updated: menuWithTiers.updated,
} as MenusRecord);
// Extract offers from tiers with their content items
if (menuWithTiers.tiers && Array.isArray(menuWithTiers.tiers)) {
for (const tier of menuWithTiers.tiers) {
if (tier.offer && !offerSet.has(tier.offer.id)) {
offerSet.add(tier.offer.id);
// Find the title from content items
let title = "";
if (tier.contentItems && Array.isArray(tier.contentItems)) {
const titleItem = tier.contentItems.find(
(item: any) => item.refId && item.refId.includes("_title"),
);
if (titleItem) {
title = titleItem.content;
}
}
// Create an enhanced offer object with tier information
const enhancedOffer = {
...tier.offer,
tierName: tier.name,
tierTitle: title,
contentItems: tier.contentItems || [],
};
relatedOffers.value.push(enhancedOffer);
}
}
}
}
}
// Sort offers by name for better display
relatedOffers.value.sort((a, b) =>
(a.name || "").localeCompare(b.name || ""),
);
}
}
loading.value = false;
});
</script>
<style scoped>
.button-group {
display: flex;
gap: 12px;
flex-wrap: wrap;
margin-top: 24px;
}
.problem-header {
margin-bottom: 20px;
}
.problem-header h2 {
margin: 0 0 12px 0;
font-size: 1.8rem;
font-weight: 600;
color: var(--ion-color-primary);
}
.problem-description {
font-size: 1.1rem;
line-height: 1.6;
color: var(--ion-text-color);
margin: 0;
}
.divider {
border-top: 1px solid var(--ion-color-medium);
margin: 24px 0;
}
.menus-section {
margin-bottom: 24px;
}
.menus-section h3,
.offers-section h3 {
font-size: 1.3rem;
font-weight: 500;
margin-bottom: 16px;
color: var(--ion-color-dark);
}
.menu-list {
display: flex;
flex-direction: column;
gap: 8px;
}
.menu-item {
padding: 12px;
background: var(--ion-color-light);
border-radius: 8px;
border-left: 4px solid var(--ion-color-primary);
}
.menu-item h4 {
margin: 0;
font-size: 1.1rem;
font-weight: 500;
}
.offers-section {
margin-bottom: 24px;
}
.offers-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 16px;
}
.offer-card {
padding: 16px;
background: var(--ion-color-light);
border-radius: 8px;
border: 1px solid var(--ion-color-medium-tint);
transition:
transform 0.2s,
box-shadow 0.2s;
position: relative;
}
.offer-card:hover {
transform: translateY(-2px);
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.tier-badge {
position: absolute;
top: 8px;
right: 8px;
padding: 4px 10px;
background: var(--ion-color-primary);
color: white;
border-radius: 12px;
font-size: 0.75rem;
font-weight: 600;
text-transform: uppercase;
}
.offer-name {
font-size: 1.15rem;
font-weight: 600;
margin-bottom: 4px;
color: var(--ion-color-dark);
padding-right: 80px; /* Make room for tier badge */
}
.offer-subtitle {
font-size: 0.95rem;
color: var(--ion-color-medium-shade);
margin-bottom: 12px;
font-style: italic;
}
.content-items {
margin: 12px 0;
padding: 12px;
background: rgba(255, 255, 255, 0.7);
border-radius: 6px;
border-left: 3px solid var(--ion-color-primary);
}
.content-item {
font-size: 0.9rem;
color: var(--ion-color-dark);
margin-bottom: 4px;
line-height: 1.4;
}
.more-items {
font-size: 0.85rem;
color: var(--ion-color-medium);
font-style: italic;
margin-top: 6px;
}
.no-offers {
text-align: center;
padding: 32px;
color: var(--ion-color-medium);
font-style: italic;
}
</style>