<template> <div v-if="visible" class="dialog-overlay"> <div class="dialog"> <h1 class="text-xl font-bold text-center mb-4 relative"> Here's one: <div class="text-lg text-center p-2 leading-none absolute right-0 -top-1" @click="cancel" > <fa icon="xmark" class="w-[1em]"></fa> </div> </h1> <span class="flex justify-between"> <span class="rounded-l border border-slate-400 bg-slate-200 px-4 py-2 flex" @click="prevIdea()" > <fa icon="chevron-left" class="m-auto" /> </span> <div class="m-2"> <span v-if="currentIdeaIndex < IDEAS.length"> <p class="text-center text-lg font-bold"> {{ IDEAS[currentIdeaIndex] }} </p> </span> <div v-if="currentIdeaIndex == IDEAS.length + 0"> <p class="text-center"> <span v-if="currentContact == null" class="text-orange-500 text-lg font-bold" > That's all your contacts. </span> <span v-else> <span class="text-lg font-bold"> Did {{ currentContact.name || AppString.NO_CONTACT_NAME }} <br /> or someone near them do anything – maybe a while ago? </span> <span class="flex justify-between"> <span /> <button class="text-center bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-2 rounded-md mt-4" @click="nextIdeaPastContacts()" > Skip Contacts <fa icon="forward" /> </button> </span> </span> </p> </div> </div> <span class="rounded-r border border-slate-400 bg-slate-200 px-4 py-2 flex" @click="nextIdea()" > <fa icon="chevron-right" class="m-auto" /> </span> </span> <button class="block w-full text-center text-md uppercase bg-gradient-to-b from-slate-400 to-slate-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-1.5 py-2 rounded-md mt-4" @click="cancel" > That's it! </button> </div> </div> </template> <script lang="ts"> import { Vue, Component } from "vue-facing-decorator"; import { AppString, NotificationIface } from "@/constants/app"; import { db } from "@/db/index"; import { Contact } from "@/db/tables/contacts"; @Component export default class GivenPrompts extends Vue { $notify!: (notification: NotificationIface, timeout?: number) => void; IDEAS = [ "Did anyone fix food for you?", "Did a family member do something for you?", "Did anyone give you a compliment?", "Who is someone you can always rely on, and how did they demonstrate that?", "Did you see anyone give to someone else?", "Is there someone who you have never met who has helped you somehow?", "How did an artist or musician or author inspire you?", "What inspiration did you get from someone who handled tragedy well?", "Did some organization give something worth respect?", "Who last gave you a good laugh?", "Do you recall anything that was given to you while you were young?", "Did someone forgive you or overlook a mistake?", "Do you know of a way an ancestor contributed to your life?", "Did anyone give you help at work?", "How did a teacher or mentor or great example help you?", ]; OTHER_PROMPTS = 1; CONTACT_PROMPT_INDEX = this.IDEAS.length; // expected after other prompts currentContact: Contact | undefined = undefined; currentIdeaIndex = 0; numContacts = 0; shownContactDbIndices: number[] = []; visible = false; AppString = AppString; async open() { this.visible = true; await db.open(); this.numContacts = await db.contacts.count(); } close() { // close the dialog but don't change values (just in case some actions are added later) this.visible = false; } /** * Get the next idea. * If it is a contact prompt, loop through. */ async nextIdea() { // if we're incrementing to the contact prompt // or if we're at the contact prompt and there was a previous contact... if ( this.currentIdeaIndex == this.CONTACT_PROMPT_INDEX - 1 || (this.currentIdeaIndex == this.CONTACT_PROMPT_INDEX && this.shownContactDbIndices.length < this.numContacts) ) { this.currentIdeaIndex = this.CONTACT_PROMPT_INDEX; this.findNextUnshownContact(); } else { // we're not at the contact prompt (or we ran out), so increment the idea index this.currentIdeaIndex = (this.currentIdeaIndex + 1) % (this.IDEAS.length + this.OTHER_PROMPTS); // ... and clear out any other prompt info this.currentContact = undefined; this.shownContactDbIndices = []; } } prevIdea() { if ( this.currentIdeaIndex == (this.CONTACT_PROMPT_INDEX + 1) % (this.IDEAS.length + this.OTHER_PROMPTS) || (this.currentIdeaIndex == this.CONTACT_PROMPT_INDEX && this.shownContactDbIndices.length < this.numContacts) ) { this.currentIdeaIndex = this.CONTACT_PROMPT_INDEX; this.findNextUnshownContact(); } else { // we're not at the contact prompt (or we ran out), so increment the idea index this.currentIdeaIndex--; if (this.currentIdeaIndex < 0) { this.currentIdeaIndex = this.IDEAS.length - 1 + this.OTHER_PROMPTS; } // ... and clear out any other prompt info this.currentContact = undefined; this.shownContactDbIndices = []; } } nextIdeaPastContacts() { this.currentIdeaIndex = 0; this.currentContact = undefined; this.shownContactDbIndices = []; } async findNextUnshownContact() { // get a random contact if (this.shownContactDbIndices.length === this.numContacts) { // no more contacts to show this.currentContact = undefined; } else { // get a random contact that hasn't been shown yet let someContactDbIndex = Math.floor(Math.random() * this.numContacts); // and guarantee that one is found by walking past shown contacts let shownContactIndex = this.shownContactDbIndices.indexOf(someContactDbIndex); while (shownContactIndex !== -1) { // increment both indices until we find a spot where "shown" skips a spot shownContactIndex = (shownContactIndex + 1) % this.numContacts; someContactDbIndex = (someContactDbIndex + 1) % this.numContacts; if ( this.shownContactDbIndices[shownContactIndex] !== someContactDbIndex ) { // we found a contact that hasn't been shown yet break; } // continue // ... and there must be at least one because shownContactDbIndices length < numContacts } this.shownContactDbIndices.push(someContactDbIndex); this.shownContactDbIndices.sort(); // get the contact at that offset await db.open(); this.currentContact = await db.contacts .offset(someContactDbIndex) .first(); } } cancel() { this.currentContact = undefined; this.currentIdeaIndex = 0; this.numContacts = 0; this.shownContactDbIndices = []; this.close(); } } </script> <style> .dialog-overlay { position: fixed; top: 0; left: 0; right: 0; bottom: 0; background-color: rgba(0, 0, 0, 0.5); display: flex; justify-content: center; align-items: center; padding: 1.5rem; } .dialog { background-color: white; padding: 1rem; border-radius: 0.5rem; width: 100%; max-width: 500px; } </style>