From f4da4b7ebb8709dfc5aa5bf43eff61b7129cd8a6 Mon Sep 17 00:00:00 2001
From: ThatOneCalculator <kainoa@t1c.dev>
Date: Fri, 9 Dec 2022 14:28:50 -0800
Subject: [PATCH] Initial migration UI

b6

Style improvements to moved
---
 locales/en-US.yml                             | 10 +-
 package.json                                  |  2 +-
 .../src/server/api/endpoints/i/move.ts        |  3 +-
 packages/client/src/components/MkMoved.vue    | 13 ++-
 .../client/src/components/MkRemoteCaution.vue |  1 -
 packages/client/src/pages/admin/migration.vue | 91 +++++++++++++++++++
 packages/client/src/pages/settings/index.vue  |  5 +
 .../client/src/pages/settings/security.vue    |  8 +-
 packages/client/src/pages/user/home.vue       |  2 +-
 packages/client/src/router.ts                 |  4 +
 10 files changed, 122 insertions(+), 17 deletions(-)
 create mode 100644 packages/client/src/pages/admin/migration.vue

diff --git a/locales/en-US.yml b/locales/en-US.yml
index aaef40b34..e6040cf0a 100644
--- a/locales/en-US.yml
+++ b/locales/en-US.yml
@@ -149,7 +149,7 @@ addAccount: "Add account"
 loginFailed: "Failed to sign in"
 showOnRemote: "View on remote instance"
 general: "General"
-accountMoved: "User has moved to a new account."
+accountMoved: "User has moved to a new account:"
 wallpaper: "Wallpaper"
 setWallpaper: "Set wallpaper"
 removeWallpaper: "Remove wallpaper"
@@ -921,6 +921,14 @@ swipeOnDesktop: "Allow mobile-style swiping on desktop"
 logoImageUrl: "Logo image URL"
 showAdminUpdates: "Indicate a new Calckey version is avaliable (admin only)"
 replayTutorial: "Replay tutorial"
+migration: "Migration"
+moveTo: "Move current account to new account"
+moveToLabel: "Account you're moving to"
+moveAccount: "Move account!"
+moveAccountDescription: "This process is irriversable. Make sure you've set up an alias for this account on your new account before moving. Please enter the tag of the account formatted like @person@instance.com"
+moveFrom: "Move to this account from an older account"
+moveFromLabel: "Old account"
+moveFromDescription: "This will set an alias of your old account so that you can move from that account to this current one. Please enter the tag of the account formatted like @person@instance.com"
 
 _sensitiveMediaDetection:
   description: "Reduces the effort of server moderation through automatically recognizing NSFW media via Machine Learning. This will slightly increase the load on the server."
diff --git a/package.json b/package.json
index 635d3614a..9940402ba 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
 	"name": "calckey",
-	"version": "13.0.0-b5",
+	"version": "13.0.0-b6",
 	"codename": "aqua",
 	"repository": {
 		"type": "git",
diff --git a/packages/backend/src/server/api/endpoints/i/move.ts b/packages/backend/src/server/api/endpoints/i/move.ts
index a1ee31d51..c67a7bdf5 100644
--- a/packages/backend/src/server/api/endpoints/i/move.ts
+++ b/packages/backend/src/server/api/endpoints/i/move.ts
@@ -40,7 +40,6 @@ export const paramDef = {
 
 // eslint-disable-next-line import/no-default-export
 export default define(meta, paramDef, async (ps, user) => {
-
-
+	// TODO
 	return;
 });
diff --git a/packages/client/src/components/MkMoved.vue b/packages/client/src/components/MkMoved.vue
index 6251d93a8..7789af001 100644
--- a/packages/client/src/components/MkMoved.vue
+++ b/packages/client/src/components/MkMoved.vue
@@ -1,8 +1,8 @@
 <template>
-<div class="_block msjugskdqo">
+<div class="msjugskd _block">
 	<i class="ph-airplane-takeoff-bold ph-lg" style="margin-right: 8px;"/>
 	{{ i18n.ts.accountMoved }}
-	<MkMention :class="$style.link" class="link" :username="acct" :host="host"/>
+	<MkMention class="link" :username="acct" :host="host"/>
 </div>
 </template>
 
@@ -16,12 +16,11 @@ defineProps<{
 }>();
 </script>
 
-<style lang="scss" module>
-.msjugskdqo {
-	font-size: 0.8em;
+<style lang="scss" scoped>
+.msjugskd {
 	padding: 16px;
-	background: var(--infoBg);
-	color: var(--infoFg);
+	background: var(--infoWarnBg);
+	color: var(--error);
 
 	> .link {
 		margin-left: 4px;
diff --git a/packages/client/src/components/MkRemoteCaution.vue b/packages/client/src/components/MkRemoteCaution.vue
index eeb097dec..4c141b7d4 100644
--- a/packages/client/src/components/MkRemoteCaution.vue
+++ b/packages/client/src/components/MkRemoteCaution.vue
@@ -12,7 +12,6 @@ defineProps<{
 
 <style lang="scss" scoped>
 .jmgmzlwq {
-	font-size: 0.8em;
 	padding: 16px;
 	background: var(--infoWarnBg);
 	color: var(--infoWarnFg);
diff --git a/packages/client/src/pages/admin/migration.vue b/packages/client/src/pages/admin/migration.vue
new file mode 100644
index 000000000..5fca8b837
--- /dev/null
+++ b/packages/client/src/pages/admin/migration.vue
@@ -0,0 +1,91 @@
+<template>
+<div class="_formRoot">
+	<FormSection>
+		<template #label>{{ i18n.ts.moveTo }}</template>
+		<FormInput v-model="alsoKnownAs" class="_formBlock">
+			<template #prefix><i class="ph-airplane-takeoff-bold ph-lg"></i></template>
+			<template #label>{{ i18n.ts.moveToLabel }}</template>
+		</FormInput>
+		<FormButton primary danger @click="move()">{{ i18n.ts.moveAccount }}</FormButton>
+		<template #caption>{{ i18n.ts.moveAccountDescription }}</template>
+	</FormSection>
+
+	<FormSection>
+		<template #label>{{ i18n.ts.moveFrom }}</template>
+		<FormInput v-model="accountAlias" class="_formBlock">
+			<template #prefix><i class="ph-airplane-landing-bold ph-lg"></i></template>
+			<template #label>{{ i18n.ts.moveFromLabel }}</template>
+		</FormInput>
+		<FormButton class="button" inline primary @click="save(accountAlias)"><i class="ph-floppy-disk-back-bold ph-lg"></i> {{ i18n.ts.save }}</FormButton>
+		<template #caption>{{ i18n.ts.moveFromDescription }}</template>
+	</FormSection>
+</div>
+</template>
+
+<script lang="ts" setup>
+import FormSection from '@/components/form/section.vue';
+import FormInput from '@/components/form/input.vue';
+import FormButton from '@/components/MkButton.vue';
+import * as os from '@/os';
+import { i18n } from '@/i18n';
+import { definePageMetadata } from '@/scripts/page-metadata';
+
+let alsoKnownAs = $ref('');
+let accountAlias = $ref('');
+
+async function save(): Promise<void> {
+	// os.apiWithDialog('i/move', {
+	// 	alsoKnownAs: alsoKnownAs,
+	// });
+}
+
+async function move(): Promise<void> {
+	// TODO: PROMPT FOR CONFIRMATION
+	os.api('i/move', {
+		alsoKnownAs: alsoKnownAs,
+	});
+}
+
+definePageMetadata({
+	title: i18n.ts.security,
+	icon: 'ph-lock-bold ph-lg',
+});
+</script>
+
+	<style lang="scss" scoped>
+	.timnmucd {
+		padding: 16px;
+
+		&:first-child {
+			border-top-left-radius: 6px;
+			border-top-right-radius: 6px;
+		}
+
+		&:last-child {
+			border-bottom-left-radius: 6px;
+			border-bottom-right-radius: 6px;
+		}
+
+		&:not(:last-child) {
+			border-bottom: solid 0.5px var(--divider);
+		}
+
+		> header {
+			display: flex;
+			align-items: center;
+
+			> .icon {
+				width: 1em;
+				margin-right: 0.75em;
+
+				&.succ {
+					color: var(--success);
+				}
+
+				&.fail {
+					color: var(--error);
+				}
+			}
+		}
+	}
+	</style>
diff --git a/packages/client/src/pages/settings/index.vue b/packages/client/src/pages/settings/index.vue
index 9a03c8f28..f6ca654ef 100644
--- a/packages/client/src/pages/settings/index.vue
+++ b/packages/client/src/pages/settings/index.vue
@@ -134,6 +134,11 @@ const menuDef = computed(() => [{
 }, {
 	title: i18n.ts.otherSettings,
 	items: [{
+		icon: 'ph-airplane-takeoff-bold ph-lg',
+		text: i18n.ts.migration,
+		to: '/settings/migration',
+		active: currentPage?.route.name === 'migration',
+	}, {
 		icon: 'ph-package-bold ph-lg',
 		text: i18n.ts.importAndExport,
 		to: '/settings/import-export',
diff --git a/packages/client/src/pages/settings/security.vue b/packages/client/src/pages/settings/security.vue
index db59f9b8a..a5fbc774e 100644
--- a/packages/client/src/pages/settings/security.vue
+++ b/packages/client/src/pages/settings/security.vue
@@ -9,7 +9,7 @@
 		<template #label>{{ i18n.ts.twoStepAuthentication }}</template>
 		<X2fa/>
 	</FormSection>
-	
+
 	<FormSection>
 		<template #label>{{ i18n.ts.signinHistory }}</template>
 		<MkPagination :pagination="pagination" disable-auto-load>
@@ -52,7 +52,7 @@ const pagination = {
 	limit: 5,
 };
 
-async function change() {
+async function change(): Promise<void> {
 	const { canceled: canceled1, result: currentPassword } = await os.inputText({
 		title: i18n.ts.currentPassword,
 		type: 'password',
@@ -78,14 +78,14 @@ async function change() {
 		});
 		return;
 	}
-	
+
 	os.apiWithDialog('i/change-password', {
 		currentPassword,
 		newPassword,
 	});
 }
 
-function regenerateToken() {
+function regenerateToken(): void {
 	os.inputText({
 		title: i18n.ts.password,
 		type: 'password',
diff --git a/packages/client/src/pages/user/home.vue b/packages/client/src/pages/user/home.vue
index 8877bce72..65ccdb88b 100644
--- a/packages/client/src/pages/user/home.vue
+++ b/packages/client/src/pages/user/home.vue
@@ -7,8 +7,8 @@
 			<!-- <div class="punished" v-if="user.isSilenced"><i class="ph-warning-bold ph-lg" style="margin-right: 8px;"></i> {{ i18n.ts.userSilenced }}</div> -->
 
 			<div class="profile">
-				<MkRemoteCaution v-if="user.host != null" :href="user.url" class="warn"/>
 				<MkMoved v-if="user.movedToUri" :host="user.movedToUri.host" :acct="user.movedToUri.username" />
+				<MkRemoteCaution v-if="user.host != null" :href="user.url" class="warn"/>
 
 				<div :key="user.id" class="_block main">
 					<div class="banner-container" :style="style">
diff --git a/packages/client/src/router.ts b/packages/client/src/router.ts
index 6f6034eed..625d65211 100644
--- a/packages/client/src/router.ts
+++ b/packages/client/src/router.ts
@@ -180,6 +180,10 @@ export const routes = [{
 		path: '/preferences-backups',
 		name: 'preferences-backups',
 		component: page(() => import('./pages/settings/preferences-backups.vue')),
+	}, {
+		path: '/migration',
+		name: 'migration',
+		component: page(() => import('./pages/settings/migration.vue')),
 	}, {
 		path: '/custom-css',
 		name: 'general',