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.
258 lines
8.1 KiB
258 lines
8.1 KiB
<template>
|
|
<QuickNav selected="Profile"></QuickNav>
|
|
<section id="Content" class="p-6 pb-24 max-w-3xl mx-auto">
|
|
<!-- Breadcrumb -->
|
|
<div id="ViewBreadcrumb" class="mb-8">
|
|
<h1 class="text-lg text-center font-light relative px-7">
|
|
<!-- Cancel -->
|
|
<router-link
|
|
:to="{ name: 'account' }"
|
|
class="text-lg text-center px-2 py-1 absolute -left-2 -top-1"
|
|
><font-awesome icon="chevron-left" class="fa-fw"></font-awesome>
|
|
</router-link>
|
|
|
|
Switch Identity
|
|
</h1>
|
|
</div>
|
|
|
|
<!-- Identity List -->
|
|
|
|
<!-- Current Identity - Display First! -->
|
|
<div
|
|
v-if="hasCorruptedIdentity"
|
|
class="block bg-slate-100 rounded-md flex items-center px-4 py-3 mb-4"
|
|
>
|
|
<font-awesome
|
|
icon="circle-check"
|
|
class="fa-fw text-red-600 text-xl mr-3"
|
|
></font-awesome>
|
|
<div class="text-sm text-slate-500">
|
|
<div class="overflow-hidden truncate">
|
|
<b>ID:</b> <code>{{ activeDid }}</code>
|
|
</div>
|
|
<b
|
|
>There is a data corruption error: this identity is selected but it is
|
|
not in storage. You cannot send any more claims with this identity
|
|
until you import the seed again. This may require reinstalling the
|
|
app; if you know how, you can also clear out the TimeSafariAccounts
|
|
IndexedDB. Be sure to back up all your Settings & Contacts first.</b
|
|
>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Other Identity/ies -->
|
|
<ul class="mb-4">
|
|
<li v-for="ident in otherIdentities" :key="ident.did">
|
|
<div class="flex items-center justify-between mb-2">
|
|
<div
|
|
:class="identityListItemClasses"
|
|
@click="switchAccount(ident.did)"
|
|
>
|
|
<font-awesome
|
|
v-if="ident.did === activeDid"
|
|
icon="circle-check"
|
|
class="fa-fw text-blue-600 text-xl mr-3"
|
|
/>
|
|
<font-awesome
|
|
v-else
|
|
icon="circle"
|
|
class="fa-fw text-slate-400 text-xl mr-3"
|
|
/>
|
|
<span class="flex-grow overflow-hidden">
|
|
<div class="text-sm text-slate-500 truncate">
|
|
<b>ID:</b> <code>{{ ident.did }}</code>
|
|
</div>
|
|
</span>
|
|
</div>
|
|
<div>
|
|
<font-awesome
|
|
v-if="ident.did === activeDid"
|
|
icon="trash-can"
|
|
class="text-slate-400 text-xl ml-2 mr-2 cursor-pointer"
|
|
@click="notifyCannotDelete()"
|
|
/>
|
|
<font-awesome
|
|
v-else
|
|
icon="trash-can"
|
|
class="text-red-600 text-xl ml-2 mr-2 cursor-pointer"
|
|
@click="deleteAccount(ident.id)"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</li>
|
|
</ul>
|
|
|
|
<!-- Actions -->
|
|
<!-- id used by puppeteer test script -->
|
|
<router-link
|
|
id="start-link"
|
|
:to="{ name: 'start' }"
|
|
:class="primaryButtonClasses"
|
|
>
|
|
Add Another Identity…
|
|
</router-link>
|
|
<a
|
|
href="#"
|
|
:class="secondaryButtonClasses"
|
|
@click="switchAccount(undefined)"
|
|
>
|
|
No Identity
|
|
</a>
|
|
</section>
|
|
</template>
|
|
<script lang="ts">
|
|
import { Component, Vue } from "vue-facing-decorator";
|
|
import { Router } from "vue-router";
|
|
|
|
import QuickNav from "../components/QuickNav.vue";
|
|
import { NotificationIface } from "../constants/app";
|
|
import { retrieveAllAccountsMetadata } from "../libs/util";
|
|
import { logger } from "../utils/logger";
|
|
import { PlatformServiceMixin } from "@/utils/PlatformServiceMixin";
|
|
import { createNotifyHelpers, TIMEOUTS } from "@/utils/notify";
|
|
import {
|
|
NOTIFY_ERROR_LOADING_ACCOUNTS,
|
|
NOTIFY_CANNOT_DELETE_ACTIVE_IDENTITY,
|
|
NOTIFY_DELETE_IDENTITY_CONFIRM,
|
|
} from "@/constants/notifications";
|
|
import { Account } from "@/db/tables/accounts";
|
|
|
|
@Component({
|
|
components: { QuickNav },
|
|
mixins: [PlatformServiceMixin],
|
|
})
|
|
export default class IdentitySwitcherView extends Vue {
|
|
$notify!: (notification: NotificationIface, timeout?: number) => void;
|
|
$router!: Router;
|
|
|
|
notify!: ReturnType<typeof createNotifyHelpers>;
|
|
|
|
public activeDid = "";
|
|
public activeDidInIdentities = false;
|
|
public apiServer = "";
|
|
public apiServerInput = "";
|
|
public otherIdentities: Array<{ id: string; did: string }> = [];
|
|
|
|
/**
|
|
* Vue lifecycle hook - Initialize notification helpers
|
|
*/
|
|
mounted() {
|
|
this.notify = createNotifyHelpers(this.$notify);
|
|
}
|
|
|
|
// =================================================
|
|
// COMPUTED PROPERTIES - Template Logic Streamlining
|
|
// =================================================
|
|
|
|
/**
|
|
* CSS classes for primary action buttons (Add Another Identity)
|
|
* Reduces template complexity for gradient button styling
|
|
*/
|
|
get primaryButtonClasses(): string {
|
|
return "block text-center text-lg font-bold uppercase bg-gradient-to-b from-blue-400 to-blue-700 shadow-[inset_0_-1px_0_0_rgba(0,0,0,0.5)] text-white px-2 py-3 rounded-md mb-2";
|
|
}
|
|
|
|
/**
|
|
* CSS classes for secondary action buttons (No Identity)
|
|
* Reduces template complexity for gradient button styling
|
|
*/
|
|
get secondaryButtonClasses(): string {
|
|
return "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 mb-8";
|
|
}
|
|
|
|
/**
|
|
* CSS classes for identity list items
|
|
* Reduces template complexity for repeated list item styling
|
|
*/
|
|
get identityListItemClasses(): string {
|
|
return "flex flex-grow items-center bg-slate-100 rounded-md px-4 py-3 mb-2 truncate cursor-pointer";
|
|
}
|
|
|
|
/**
|
|
* Detects if there's a data corruption issue with the active identity
|
|
* Shows warning when an identity is selected but not found in storage
|
|
*/
|
|
get hasCorruptedIdentity(): boolean {
|
|
return Boolean(this.activeDid && !this.activeDidInIdentities);
|
|
}
|
|
|
|
// =================================================
|
|
// HELPER METHODS - Template Logic Streamlining
|
|
// =================================================
|
|
|
|
/**
|
|
* Formats account data for display in the identity list
|
|
* Consolidates account processing logic from template
|
|
* @param account - Account object from database
|
|
* @returns Formatted account object for display
|
|
*/
|
|
formatAccountForDisplay(account: Account): { id: string; did: string } {
|
|
return {
|
|
id: (account.id ?? 0).toString(),
|
|
did: account.did,
|
|
};
|
|
}
|
|
|
|
// =================================================
|
|
// COMPONENT METHODS
|
|
// =================================================
|
|
|
|
async created() {
|
|
try {
|
|
const settings = await this.$accountSettings();
|
|
this.activeDid = settings.activeDid || "";
|
|
this.apiServer = settings.apiServer || "";
|
|
this.apiServerInput = settings.apiServer || "";
|
|
|
|
const accounts = await retrieveAllAccountsMetadata();
|
|
for (let n = 0; n < accounts.length; n++) {
|
|
const acct = accounts[n];
|
|
this.otherIdentities.push(this.formatAccountForDisplay(acct));
|
|
if (acct.did && this.activeDid === acct.did) {
|
|
this.activeDidInIdentities = true;
|
|
}
|
|
}
|
|
} catch (err) {
|
|
this.notify.error(NOTIFY_ERROR_LOADING_ACCOUNTS.message, TIMEOUTS.LONG);
|
|
logger.error("Telling user to clear cache at page create because:", err);
|
|
}
|
|
}
|
|
|
|
async switchAccount(did?: string) {
|
|
// Save the new active DID to master settings
|
|
await this.$saveSettings({ activeDid: did });
|
|
|
|
// Check if we need to load user-specific settings for the new DID
|
|
if (did) {
|
|
try {
|
|
await this.$accountSettings(did);
|
|
} catch (error) {
|
|
// Handle error silently - user settings will be loaded when needed
|
|
}
|
|
}
|
|
|
|
// Navigate to home page to trigger the watcher
|
|
this.$router.push({ name: "home" });
|
|
}
|
|
|
|
async deleteAccount(id: string) {
|
|
this.notify.confirm(
|
|
NOTIFY_DELETE_IDENTITY_CONFIRM.text,
|
|
async () => {
|
|
await this.$exec(`DELETE FROM accounts WHERE id = ?`, [id]);
|
|
this.otherIdentities = this.otherIdentities.filter(
|
|
(ident) => ident.id !== id,
|
|
);
|
|
},
|
|
-1,
|
|
);
|
|
}
|
|
|
|
notifyCannotDelete() {
|
|
this.notify.warning(
|
|
NOTIFY_CANNOT_DELETE_ACTIVE_IDENTITY.message,
|
|
TIMEOUTS.SHORT,
|
|
);
|
|
}
|
|
}
|
|
</script>
|
|
|