You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
215 lines
6.3 KiB
215 lines
6.3 KiB
1 year ago
|
<template>
|
||
|
<div v-if="visible" class="dialog-overlay">
|
||
|
<div class="dialog">
|
||
|
<h1 class="text-xl font-bold text-center mb-4">Here's one:</h1>
|
||
|
<span class="flex justify-between h-24">
|
||
|
<span
|
||
|
class="rounded-l border border-slate-400 bg-slate-200 h-full px-4 py-2 flex h-screen"
|
||
|
@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 text-lg font-bold">
|
||
|
Did this person or someone near them do something – maybe a
|
||
|
while ago?
|
||
|
<br />
|
||
|
<span v-if="currentContact?.name == null" class="text-orange-500">
|
||
|
That's all your contacts.
|
||
|
</span>
|
||
|
<span v-else>{{
|
||
|
currentContact.name || AppString.NO_CONTACT_NAME
|
||
|
}}</span>
|
||
|
</p>
|
||
|
</div>
|
||
|
</div>
|
||
|
|
||
|
<span
|
||
|
class="rounded-r border border-slate-400 bg-slate-200 h-full px-4 py-2 flex h-screen"
|
||
|
@click="nextIdea()"
|
||
|
>
|
||
|
<fa icon="chevron-right" class="m-auto" />
|
||
|
</span>
|
||
|
</span>
|
||
|
<button
|
||
|
class="block w-full text-center text-md uppercase bg-slate-500 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 } from "@/constants/app";
|
||
|
import { db } from "@/db/index";
|
||
|
import { Contact } from "@/db/tables/contacts";
|
||
|
|
||
|
interface Notification {
|
||
|
group: string;
|
||
|
type: string;
|
||
|
title: string;
|
||
|
text: string;
|
||
|
}
|
||
|
|
||
|
@Component
|
||
|
export default class GivenPrompts extends Vue {
|
||
|
$notify!: (notification: Notification, timeout?: number) => void;
|
||
|
|
||
|
IDEAS = [
|
||
|
"Did anyone fix food for you?",
|
||
|
"Did a family member do something for you?",
|
||
|
"Did anyone give you a compliment?",
|
||
|
"Did you see anyone give to someone else?",
|
||
|
"Did anyone give you a good laugh?",
|
||
|
"Do you recall anything that was given to you while you were young?",
|
||
|
"Do you know of a way an ancestor contributed to your life?",
|
||
|
];
|
||
|
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.currentContact)
|
||
|
) {
|
||
|
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.currentContact)
|
||
|
) {
|
||
|
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 = [];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
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>
|