Hello from MCP server

List Files | Just Commands | Repo | Logs

← back |
<template>
  <BaseLayout title="Technician - View Job">
    <!-- Toolbar at top of screen -->
    <Toolbar :force-step2="true" @help-clicked="openInfoModal" />

    <div class="view-job-container">
      <h2 class="view-job-title">Is this the job you're working on?</h2>

      <div class="yes-no-buttons">
        <YesButton :disabled="!isButtonEnabled" @click="handleSelectJob" />
        <button
          :disabled="!isButtonEnabled"
          @click="handleNo"
          class="no-button"
        >
          No
        </button>
      </div>

      <Divider />

      <div class="content-section">
        <h3 class="job-name">{{ problem?.name || "Loading..." }}</h3>
        <div
          class="description"
          v-html="formatDescriptionWithHashtags(problem?.description)"
        ></div>
      </div>

      <!-- Action Bar -->
      <ActionBar title="Check Steps" :flash="true" :disabled="true" @next="handleSelectJob" />
    </div>

    <!-- Info Modal -->
    <ion-modal :is-open="isInfoModalOpen" @didDismiss="closeInfoModal">
      <ion-header>
        <ion-toolbar>
          <ion-title>Session Store</ion-title>
          <ion-buttons slot="end">
            <ion-button @click="closeInfoModal">Close</ion-button>
          </ion-buttons>
        </ion-toolbar>
      </ion-header>
      <ion-content class="ion-padding">
        <div class="info-content">
          <pre>{{ JSON.stringify(sessionStore.$state, null, 2) }}</pre>
        </div>
      </ion-content>
    </ion-modal>
  </BaseLayout>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted } from "vue";
import { useRoute, useRouter } from "vue-router";
import {
  IonIcon,
  IonModal,
  IonHeader,
  IonToolbar,
  IonTitle,
  IonButtons,
  IonButton,
  IonContent,
} from "@ionic/vue";
import { arrowBack, helpCircleOutline, construct } from "ionicons/icons";
import BaseLayout from "@/components/BaseLayout.vue";
import Toolbar from "@/components/Toolbar.vue";
import ActionBar from "@/components/ActionBar.vue";
import Divider from "@/components/Divider.vue";
import YesButton from "@/components/YesButton.vue";
import { getDb } from "@/dataAccess/getDb";
import { getApi } from "@/dataAccess/getApi";
import { useSessionStore } from "@/stores/session";
import type { ProblemsRecord } from "@/pocketbase-types";

const route = useRoute();
const router = useRouter();
const sessionStore = useSessionStore();

const problem = ref<ProblemsRecord | null>(null);
const isInfoModalOpen = ref(false);
const isButtonEnabled = ref(false);
let enableButtonTimeout: ReturnType<typeof setTimeout> | null = null;

// Find the job in the session that matches this problem
const currentJob = computed(() => {
  if (!problem.value) return null;
  return sessionStore.jobs.find((job) => job.problem?.id === problem.value?.id);
});

onMounted(async () => {
  const problemId = route.params.problemId as string;
  const db = await getDb();

  if (db && problemId) {
    problem.value = await db.problems.byId(problemId);
  }

  // Load session first to ensure we have the latest data
  await sessionStore.load();

  // Set step1 to true when viewing a job
  sessionStore.appProgress.step1 = true;
  await sessionStore.save();

  // Enable button after 1.5 seconds
  isButtonEnabled.value = false;
  enableButtonTimeout = setTimeout(() => {
    isButtonEnabled.value = true;
  }, 1500);
});

onUnmounted(() => {
  // Clear timeout when navigating away
  if (enableButtonTimeout) {
    clearTimeout(enableButtonTimeout);
    enableButtonTimeout = null;
  }
});

const goBack = () => {
  router.back();
};

const openInfoModal = () => {
  isInfoModalOpen.value = true;
};

const closeInfoModal = () => {
  isInfoModalOpen.value = false;
};

const formatDescriptionWithHashtags = (description: string | undefined) => {
  if (!description) return "";

  // Split into lines and process each one
  const lines = description.split("\n");
  const processedLines = lines.map((line) => {
    if (line.includes(":")) {
      return '<span class="colon-line">' + line + "</span>";
    }
    return line;
  });

  // Join lines with <br> tags
  let formatted = processedLines.join("<br>");

  // Find the first # and style everything from there onwards
  const hashIndex = formatted.indexOf("#");
  if (hashIndex === -1) return formatted;

  const beforeHash = formatted.substring(0, hashIndex);
  const afterHash = formatted.substring(hashIndex);

  return beforeHash + '<span class="hashtag">' + afterHash + "</span>";
};

const handleSelectJob = async () => {
  if (problem.value) {
    // Set step2 to true when check steps is clicked
    if (!sessionStore.appProgress.step2) {
      sessionStore.appProgress.step2 = true;
      await sessionStore.save();
    }
    // Navigate to check-steps with problem ID
    router.push(`/check-steps/${problem.value.id}`);
  }
};

const handleNo = async () => {
  // Set step2 to false
  sessionStore.appProgress.step2 = false;
  await sessionStore.save();

  // Navigate back to find-job (step 1)
  router.push('/find-job');
};
</script>

<style scoped>
:deep(.ion-page) {
  animation: none !important;
  transform: none !important;
  transition: none !important;
}

.view-job-container {
  padding: 20px;
  max-width: 1200px;
  margin: 0 auto;
  animation: none !important;
  transform: none !important;
  transition: none !important;
}

.view-job-title {
  margin: 0 0 32px 0;
  color: #ffffff;
  font-size: 32px;
  font-weight: 600;
  text-align: center;
  font-variant: small-caps;
}

.job-name {
  margin: 0 0 16px 0;
  color: #ffffff;
  font-size: 24px;
  font-weight: 600;
}

.header-section {
  margin-bottom: 32px;
}

.title-container {
  position: relative;
  margin-bottom: 24px;
}

.title-icons {
  position: absolute;
  left: 12px;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  gap: 16px;
}

.title-icons-right {
  position: absolute;
  right: 12px;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  gap: 16px;
}

.back-icon-wrapper {
  position: relative;
  display: inline-block;
  background-color: var(--ion-color-tertiary);
  padding: 8px;
  border-radius: 4px;
}

.title-icons ion-icon {
  font-size: 48px;
}

.title-icons-right ion-icon {
  font-size: 48px;
}

.clickable-icon {
  cursor: pointer;
  transition:
    transform 0.2s ease,
    color 0.2s ease;
}

.clickable-icon:hover {
  transform: scale(1.1);
  color: var(--ion-color-primary-shade);
}

.clickable-icon:active {
  transform: scale(0.95);
}

.page-title {
  margin: 0;
  color: #ffffff;
  font-size: 48px;
  font-weight: 700;
  text-align: center;
  font-variant: small-caps;
  padding-left: 80px;
  padding-right: 80px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
}

.construction-icon {
  width: 48px;
  height: 48px;
  object-fit: contain;
}

.content-section {
  padding: 0 20px 100px 20px;
}

.description {
  color: #ffffff;
  font-size: 18px;
  line-height: 1.6;
  max-width: 1000px;
  margin: 0 auto;
}

.description :deep(.hashtag) {
  color: var(--ion-color-medium);
  font-size: 16px;
}

.description :deep(.colon-line) {
  display: inline-block;
  margin-top: 16px;
}

.yes-no-buttons {
  display: flex;
  justify-content: center;
  gap: 16px;
  margin-bottom: 24px;
}

.no-button {
  display: inline-block;
  padding: 16px 48px;
  font-size: 20px;
  font-weight: 600;
  color: #ffffff;
  background-color: var(--ion-color-secondary);
  border: none;
  border-radius: 8px;
  cursor: pointer;
  transition: transform 0.2s ease, background-color 0.2s ease;
}

.no-button:hover:not(:disabled) {
  transform: scale(1.05);
  background-color: var(--ion-color-secondary-shade);
}

.no-button:active:not(:disabled) {
  transform: scale(0.95);
}

.no-button:disabled {
  background-color: var(--ion-background-color);
  border: 3px solid var(--ion-color-secondary);
  color: var(--ion-color-secondary);
  opacity: 0.6;
  cursor: not-allowed;
}

.no-button:disabled:hover {
  background-color: var(--ion-background-color);
  transform: none;
}

/* Mobile adjustments */
@media (max-width: 767px) {
  .view-job-container {
    padding: 16px;
  }

  .page-title {
    font-size: 36px;
  }

  .description {
    font-size: 16px;
  }

  .no-button {
    font-size: 18px;
    padding: 12px 36px;
  }
}

/* Info Modal Styles */
.info-content {
  color: var(--ion-color-dark);
}

.info-content pre {
  background: var(--ion-color-light);
  padding: 16px;
  border-radius: 8px;
  overflow-x: auto;
  font-size: 12px;
  line-height: 1.5;
  white-space: pre-wrap;
  word-wrap: break-word;
}
</style>