Hello from MCP server

List Files | Just Commands | Repo | Logs

← back |
<template>
  <div class="toolbar">
    <div class="toolbar-content">
      <div class="toolbar-left">
        <ion-icon :icon="arrowUndo" @click="goBack" class="clickable-icon" size="large"></ion-icon>
        <ion-icon v-if="showClearIcon" :icon="closeCircleOutline" @click="handleClearClick" class="clickable-icon" size="large"></ion-icon>
      </div>
      <div v-if="!hideProgress" class="toolbar-icons">
        <ion-icon
          v-for="(iconData, index) in progressIcons"
          :key="index"
          :icon="iconData.icon"
          :color="iconData.color"
          size="large"
        ></ion-icon>
      </div>
      <div class="toolbar-right">
        <div class="percent-button clickable-icon" :class="{ 'percent-active': discountActive }" @click="handlePercentClick">%</div>
        <ion-icon :icon="helpCircleOutline" @click="handleHelpClick" class="clickable-icon" size="large"></ion-icon>
        <ion-icon :icon="arrowRedo" @click="goForward" class="clickable-icon" size="large"></ion-icon>
      </div>
      <slot></slot>
    </div>
  </div>
</template>

<script setup lang="ts">
import { computed } from 'vue';
import { useRouter } from 'vue-router';
import { IonIcon } from '@ionic/vue';
import { ellipse, ellipseOutline, arrowUndo, arrowRedo, helpCircleOutline, closeCircleOutline } from 'ionicons/icons';
import { useSessionStore } from '@/stores/session';

// Customer Toolbar component - for customer-facing pages
const sessionStore = useSessionStore();
const router = useRouter();

// Props
const props = withDefaults(defineProps<{
  forceStep1?: boolean;
  forceStep2?: boolean;
  forceStep3?: boolean;
  forceStep4?: boolean;
  forceStep5?: boolean;
  currentStep?: number; // The current step index (0-based)
  discountActive?: boolean; // Whether the SA discount is active
  showClearIcon?: boolean; // Whether to show the clear selections icon
  hideProgress?: boolean; // Whether to hide the progress bar
}>(), {
  forceStep1: false,
  forceStep2: false,
  forceStep3: false,
  forceStep4: false,
  forceStep5: false,
  currentStep: -1,
  discountActive: false,
  showClearIcon: false,
  hideProgress: false
});

// Define emits for parent components to listen to
const emit = defineEmits(['help-clicked', 'percent-clicked', 'clear-clicked']);

// Handle help icon click
const handleHelpClick = () => {
  emit('help-clicked');
};

// Handle percent button click
const handlePercentClick = () => {
  emit('percent-clicked');
};

// Handle clear icon click
const handleClearClick = () => {
  emit('clear-clicked');
};

// Handle back arrow click
const goBack = () => {
  router.back();
};

// Handle forward arrow click - navigate to next step
const goForward = () => {
  if (props.currentStep < 0) {
    router.forward();
    return;
  }

  const numJobs = sessionStore.jobs.length;
  const totalSteps = numJobs + 2; // N menus + review + payment
  const nextStep = props.currentStep + 1;

  if (nextStep >= totalSteps) {
    // Already at last step
    return;
  }

  // Sort jobs by price (highest first)
  const sortedJobs = [...sessionStore.jobs].sort((a, b) => {
    const getPriceA = a.selectedPrice ? parseFloat(a.selectedPrice) : ((a.baseHours || 0) + (a.extraTime || 0));
    const getPriceB = b.selectedPrice ? parseFloat(b.selectedPrice) : ((b.baseHours || 0) + (b.extraTime || 0));
    return getPriceB - getPriceA;
  });

  if (nextStep < numJobs) {
    // Navigate to next job menu
    const nextJob = sortedJobs[nextStep];
    router.push(`/job/${nextJob.id}/show/legacy`);
  } else if (nextStep === numJobs) {
    // Navigate to review/cart
    router.push('/cart/');
  } else if (nextStep === numJobs + 1) {
    // Navigate to payment (when implemented)
    // router.push('/payment');
  }
};

const progressIcons = computed(() => {
  const icons = [];

  // Calculate number of steps dynamically
  // Number of jobs (menus) + 2 (review + payment)
  const numJobs = sessionStore.jobs.length;
  const totalSteps = numJobs + 2; // N menus + review + payment

  // Sort jobs by price (highest first) to match menu order
  const sortedJobs = [...sessionStore.jobs].sort((a, b) => {
    const getPriceA = a.selectedPrice ? parseFloat(a.selectedPrice) : ((a.baseHours || 0) + (a.extraTime || 0));
    const getPriceB = b.selectedPrice ? parseFloat(b.selectedPrice) : ((b.baseHours || 0) + (b.extraTime || 0));
    return getPriceB - getPriceA;
  });

  const getIconData = (stepIndex: number, forced: boolean = false) => {
    // Check if this step is completed in the customerProgress array
    const progressArray = sessionStore.customerProgress as any;
    const stepValue = progressArray[stepIndex];

    if (stepValue === "pending") {
      return { icon: ellipse, color: "warning" };
    }

    // For menu steps (0 to numJobs-1), check if the corresponding job has a selected offer
    let isComplete = forced || stepValue === true;
    if (stepIndex < numJobs) {
      const job = sortedJobs[stepIndex];
      if (job) {
        // A menu is complete if it has a selected offer
        isComplete = !!(job.selectedOffer && job.selectedPrice);
      }
    }

    // If this is the current step, show filled success icon
    if (stepIndex === props.currentStep) {
      return { icon: ellipse, color: "success" };
    }

    // If complete (has item in cart), show filled success icon
    // If not complete, show outline success icon
    return { icon: isComplete ? ellipse : ellipseOutline, color: "success" };
  };

  // Generate icons for each step dynamically
  for (let i = 0; i < totalSteps; i++) {
    // Check if this step should be forced
    let forced = false;
    if (i === 0 && props.forceStep1) forced = true;
    if (i === 1 && props.forceStep2) forced = true;
    if (i === 2 && props.forceStep3) forced = true;
    if (i === 3 && props.forceStep4) forced = true;
    if (i === 4 && props.forceStep5) forced = true;

    icons.push(getIconData(i, forced));
  }

  return icons;
});
</script>

<style scoped>
.toolbar {
  position: relative;
  background-color: var(--ion-background-color);
  padding: 20px;
  border-bottom: 3px solid var(--ion-color-primary);
}

.toolbar-content {
  max-width: 1200px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  position: relative;
}

.toolbar-left {
  display: flex;
  align-items: center;
  gap: 16px;
}

.toolbar-left ion-icon {
  color: var(--ion-color-primary);
}

.clickable-icon {
  cursor: pointer;
}

.toolbar-right {
  display: flex;
  align-items: center;
  gap: 16px;
}

.toolbar-right ion-icon {
  color: var(--ion-color-primary);
}

.toolbar-icons {
  display: flex;
  gap: 16px;
  align-items: center;
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
}

.toolbar-icons ion-icon {
  color: var(--ion-color-primary);
}

.percent-button {
  color: var(--ion-color-medium);
  font-size: 32px;
  font-weight: 700;
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  transition: color 0.2s ease;
}

.percent-active {
  color: var(--ion-color-primary);
}
</style>