Browse Source

add a prompt for things for which to express gratitude

starred-projects
Trent Larson 8 months ago
parent
commit
b38ebc45e1
  1. 7
      project.task.yaml
  2. 214
      src/components/GiftedPrompts.vue
  3. 2
      src/constants/app.ts
  4. 5
      src/views/ContactsView.vue
  5. 17
      src/views/HomeView.vue

7
project.task.yaml

@ -1,9 +1,14 @@
tasks:
- fix timeSafari.org cert renewals
- anchor hash into BTC
- add more detail on TimeSafari.org
- add button to front page to prompt for ideas for gratitude
- checkboxes: show in order, show non-person-oriented messages, show only contacts, show only projects
- show previous on "Your" screen
- allow user to add a time when they want their daily notification
- prompt for the name directly when they visit the QR scan page
- bug - user on new phone did not prompt him to install
- image on give
- Show a camera to take a picture
- Scale the image to a reasonable size

214
src/components/GiftedPrompts.vue

@ -0,0 +1,214 @@
<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 &ndash; 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>

2
src/constants/app.ts

@ -11,6 +11,8 @@ export enum AppString {
PROD_PUSH_SERVER = "https://timesafari.app",
TEST1_PUSH_SERVER = "https://test.timesafari.app",
TEST2_PUSH_SERVER = "https://timesafari-pwa.anomalistlabs.com",
NO_CONTACT_NAME = "(no name)",
}
export const DEFAULT_ENDORSER_API_SERVER = AppString.TEST_ENDORSER_API_SERVER;

5
src/views/ContactsView.vue

@ -98,7 +98,7 @@
class="inline-block align-text-bottom border border-slate-300 rounded"
@click="showLargeIdenticon = contact.did"
></EntityIcon>
{{ contact.name || "(no name)" }}
{{ contact.name || AppString.NO_CONTACT_NAME }}
<button
class="text-sm uppercase bg-slate-500 text-white px-1 rounded-md"
@click="
@ -289,7 +289,7 @@ import * as R from "ramda";
import { IIdentifier } from "@veramo/core";
import { Component, Vue } from "vue-facing-decorator";
import { NotificationIface } from "@/constants/app";
import { AppString, NotificationIface } from "@/constants/app";
import { accountsDB, db } from "@/db/index";
import { Contact } from "@/db/tables/contacts";
import { MASTER_SETTINGS_KEY, Settings } from "@/db/tables/settings";
@ -349,6 +349,7 @@ export default class ContactsView extends Vue {
showGiveConfirmed = true;
showLargeIdenticon = "";
AppString = AppString;
libsUtil = libsUtil;
async created() {

17
src/views/HomeView.vue

@ -104,7 +104,15 @@
<div v-else>
<!-- activeDid && isRegistered -->
<h2 class="text-xl font-bold mb-4">Record Something Given</h2>
<div class="flex justify-between mb-4">
<h2 class="text-xl font-bold">Record Something Given</h2>
<button
@click="openGiftedPrompts()"
class="block text-center text-md font-bold bg-blue-500 text-white px-2 py-3 rounded-md"
>
If you want an idea...
</button>
</div>
<ul class="grid grid-cols-4 gap-x-3 gap-y-5 text-center mb-5">
<li @click="openDialog()">
@ -160,6 +168,7 @@
message="Received from"
showGivenToUser="true"
/>
<GiftedPrompts ref="giftedPrompts" />
<!-- Results List -->
<div class="bg-slate-100 rounded-md overflow-hidden px-4 py-3 mb-4">
@ -226,6 +235,7 @@ import { Component, Vue } from "vue-facing-decorator";
import EntityIcon from "@/components/EntityIcon.vue";
import GiftedDialog from "@/components/GiftedDialog.vue";
import GiftedPrompts from "@/components/GiftedPrompts.vue";
import InfiniteScroll from "@/components/InfiniteScroll.vue";
import QuickNav from "@/components/QuickNav.vue";
import TopMessage from "@/components/TopMessage.vue";
@ -252,6 +262,7 @@ interface Notification {
@Component({
components: {
GiftedDialog,
GiftedPrompts,
QuickNav,
EntityIcon,
InfiniteScroll,
@ -500,5 +511,9 @@ export default class HomeView extends Vue {
openDialog(giver: GiverInputInfo) {
(this.$refs.customDialog as GiftedDialog).open(giver);
}
openGiftedPrompts() {
(this.$refs.giftedPrompts as GiftedPrompts).open();
}
}
</script>

Loading…
Cancel
Save