|
|
|
<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>
|