Skip to content

Commit 1febb0f

Browse files
authored
feature: Discord link and unlink move from the settings sidebar to the Linked Accounts page (#842)
1 parent 45a580e commit 1febb0f

21 files changed

Lines changed: 215 additions & 99 deletions
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
<script setup lang="ts">
2+
import { computed, ref } from "vue";
3+
import { useI18n } from "vue-i18n";
4+
import { CheckCircle2, Link, Unlink } from "lucide-vue-next";
5+
import { DiscordLogoIcon } from "@radix-icons/vue";
6+
import { Button } from "~/components/ui/button";
7+
import { toast } from "~/components/ui/toast";
8+
import {
9+
AlertDialog,
10+
AlertDialogCancel,
11+
AlertDialogContent,
12+
AlertDialogDescription,
13+
AlertDialogFooter,
14+
AlertDialogHeader,
15+
AlertDialogTitle,
16+
} from "~/components/ui/alert-dialog";
17+
import FiveStackToolTip from "~/components/FiveStackToolTip.vue";
18+
import FadeSwap from "~/components/ui/transitions/FadeSwap.vue";
19+
import { generateMutation } from "~/graphql/graphqlGen";
20+
21+
const { t } = useI18n();
22+
23+
const linked = computed(() => useAuthStore().hasDiscordLinked);
24+
25+
const showUnlinkConfirm = ref(false);
26+
const unlinking = ref(false);
27+
28+
function linkDiscord() {
29+
window.location.href = `https://${useRuntimeConfig().public.webDomain}/auth/discord?redirect=${encodeURIComponent(window.location.toString())}`;
30+
}
31+
32+
async function confirmUnlink() {
33+
if (unlinking.value) {
34+
return;
35+
}
36+
unlinking.value = true;
37+
try {
38+
const { $apollo } = useNuxtApp();
39+
await ($apollo as any).mutate({
40+
mutation: generateMutation({
41+
unlinkDiscord: { success: true },
42+
}),
43+
});
44+
showUnlinkConfirm.value = false;
45+
await useAuthStore().getMe();
46+
toast({ title: t("pages.settings.account.discord.unlinked") });
47+
} finally {
48+
unlinking.value = false;
49+
}
50+
}
51+
</script>
52+
53+
<template>
54+
<FadeSwap>
55+
<div
56+
v-if="linked"
57+
key="linked"
58+
class="rounded-lg border border-border bg-card/50 overflow-hidden"
59+
>
60+
<div class="flex items-center justify-between gap-3 px-4 py-3">
61+
<div class="flex items-center gap-2.5 min-w-0">
62+
<span
63+
class="shrink-0 w-7 h-7 rounded-md flex items-center justify-center bg-emerald-500/15 text-emerald-400"
64+
>
65+
<CheckCircle2 class="w-4 h-4" />
66+
</span>
67+
<div class="min-w-0">
68+
<div class="text-sm font-medium leading-tight">
69+
{{ $t("pages.settings.account.discord.title") }}
70+
</div>
71+
<div class="text-xs text-muted-foreground">
72+
{{ $t("pages.settings.account.discord.linked") }}
73+
</div>
74+
</div>
75+
</div>
76+
77+
<FiveStackToolTip side="bottom">
78+
<template #trigger>
79+
<Button
80+
size="icon"
81+
variant="ghost"
82+
class="h-8 w-8 shrink-0 text-muted-foreground hover:text-destructive hover:bg-destructive/10 [&_svg]:size-3.5"
83+
:aria-label="$t('pages.settings.account.discord.unlink')"
84+
@click="showUnlinkConfirm = true"
85+
>
86+
<Unlink />
87+
</Button>
88+
</template>
89+
{{ $t("pages.settings.account.discord.unlink") }}
90+
</FiveStackToolTip>
91+
</div>
92+
</div>
93+
94+
<div
95+
v-else
96+
key="unlinked"
97+
class="rounded-lg border border-border bg-card/50 overflow-hidden"
98+
>
99+
<div class="flex items-center justify-between gap-3 px-4 py-3">
100+
<div class="flex items-center gap-2.5 min-w-0">
101+
<span
102+
class="shrink-0 w-7 h-7 rounded-md flex items-center justify-center bg-muted text-muted-foreground"
103+
>
104+
<DiscordLogoIcon class="w-4 h-4" />
105+
</span>
106+
<div class="min-w-0">
107+
<div class="text-sm font-medium leading-tight">
108+
{{ $t("pages.settings.account.discord.title") }}
109+
</div>
110+
<div class="text-xs text-muted-foreground">
111+
{{ $t("pages.settings.account.discord.description") }}
112+
</div>
113+
</div>
114+
</div>
115+
116+
<Button
117+
variant="outline"
118+
size="sm"
119+
class="shrink-0"
120+
@click="linkDiscord"
121+
>
122+
<Link />
123+
{{ $t("pages.settings.account.discord.link") }}
124+
</Button>
125+
</div>
126+
</div>
127+
</FadeSwap>
128+
129+
<AlertDialog v-model:open="showUnlinkConfirm">
130+
<AlertDialogContent>
131+
<AlertDialogHeader>
132+
<AlertDialogTitle>{{
133+
$t("pages.settings.account.discord.unlink_dialog.title")
134+
}}</AlertDialogTitle>
135+
<AlertDialogDescription>
136+
{{ $t("pages.settings.account.discord.unlink_dialog.description") }}
137+
</AlertDialogDescription>
138+
</AlertDialogHeader>
139+
<AlertDialogFooter>
140+
<AlertDialogCancel :disabled="unlinking">{{
141+
$t("common.cancel")
142+
}}</AlertDialogCancel>
143+
<Button
144+
variant="destructive"
145+
:loading="unlinking"
146+
@click="confirmUnlink"
147+
>
148+
{{ $t("pages.settings.account.discord.unlink_dialog.confirm") }}
149+
</Button>
150+
</AlertDialogFooter>
151+
</AlertDialogContent>
152+
</AlertDialog>
153+
</template>

‎components/settings/ProfileSettingsShell.vue‎

Lines changed: 1 addition & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,15 @@
11
<script setup lang="ts">
2-
import { Button } from "@/components/ui/button";
32
import {
43
Select,
54
SelectContent,
65
SelectItem,
76
SelectTrigger,
87
SelectValue,
98
} from "@/components/ui/select";
10-
import { generateMutation } from "~/graphql/graphqlGen";
11-
import {
12-
AlertDialog,
13-
AlertDialogAction,
14-
AlertDialogCancel,
15-
AlertDialogContent,
16-
AlertDialogDescription,
17-
AlertDialogFooter,
18-
AlertDialogHeader,
19-
AlertDialogTitle,
20-
AlertDialogTrigger,
21-
} from "@/components/ui/alert-dialog";
22-
import { Link, Unlink } from "lucide-vue-next";
23-
import { toast } from "@/components/ui/toast";
249
import SettingsSideTabs from "~/components/settings/SettingsSideTabs.vue";
2510
2611
const { t: $t } = useI18n();
2712
28-
const hasDiscordLinked = computed(() => useAuthStore().hasDiscordLinked);
29-
const supportsDiscordBot = computed(
30-
() => useApplicationSettingsStore().supportsDiscordBot,
31-
);
32-
33-
const showUnlinkDiscordDialog = ref(false);
34-
3513
const navItems = computed(() => {
3614
const items: { path: string; label: string }[] = [
3715
{
@@ -103,32 +81,6 @@ watch(
10381
}
10482
},
10583
);
106-
107-
function linkDiscord() {
108-
if (hasDiscordLinked.value) return;
109-
window.location.href = `https://${useRuntimeConfig().public.webDomain}/auth/discord?redirect=${encodeURIComponent(window.location.toString())}`;
110-
}
111-
112-
async function unlinkDiscord() {
113-
const { $apollo } = useNuxtApp();
114-
await ($apollo as any).mutate({
115-
mutation: generateMutation({
116-
unlinkDiscord: [
117-
{},
118-
{
119-
success: true,
120-
},
121-
],
122-
}),
123-
});
124-
125-
showUnlinkDiscordDialog.value = false;
126-
useAuthStore().getMe();
127-
128-
toast({
129-
title: $t("pages.settings.account.discord.unlinked"),
130-
});
131-
}
13284
</script>
13385

13486
<template>
@@ -173,28 +125,7 @@ async function unlinkDiscord() {
173125
:items="navItems"
174126
:active-path="resolvedPath"
175127
:aria-label="$t('ui.tooltips.settings_section')"
176-
>
177-
<template #actions>
178-
<Button
179-
v-if="hasDiscordLinked"
180-
variant="ghost"
181-
class="w-full justify-start px-3 text-left text-muted-foreground transition-colors duration-200 hover:bg-[hsl(var(--tac-amber)/0.08)] hover:text-foreground"
182-
@click.stop.prevent="showUnlinkDiscordDialog = true"
183-
>
184-
<Unlink class="mr-2 h-4 w-4" />
185-
{{ $t("pages.settings.account.discord.unlink") }}
186-
</Button>
187-
<Button
188-
v-else-if="supportsDiscordBot"
189-
variant="ghost"
190-
class="w-full justify-start px-3 text-left text-muted-foreground transition-colors duration-200 hover:bg-[hsl(var(--tac-amber)/0.08)] hover:text-foreground"
191-
@click="linkDiscord"
192-
>
193-
<Link class="mr-2 h-4 w-4" />
194-
{{ $t("pages.settings.account.discord.link") }}
195-
</Button>
196-
</template>
197-
</SettingsSideTabs>
128+
/>
198129
</aside>
199130
<!-- Every account page is a narrow form, so the measure is applied here
200131
rather than asking each one to wrap itself in SettingsPage. -->
@@ -206,26 +137,4 @@ async function unlinkDiscord() {
206137
</div>
207138
</div>
208139
</div>
209-
210-
<AlertDialog :open="showUnlinkDiscordDialog">
211-
<AlertDialogTrigger asChild> </AlertDialogTrigger>
212-
<AlertDialogContent>
213-
<AlertDialogHeader>
214-
<AlertDialogTitle>{{
215-
$t("pages.settings.account.discord.unlink_dialog.title")
216-
}}</AlertDialogTitle>
217-
<AlertDialogDescription>
218-
{{ $t("pages.settings.account.discord.unlink_dialog.description") }}
219-
</AlertDialogDescription>
220-
</AlertDialogHeader>
221-
<AlertDialogFooter>
222-
<AlertDialogCancel @click="showUnlinkDiscordDialog = false">
223-
{{ $t("common.cancel") }}
224-
</AlertDialogCancel>
225-
<AlertDialogAction @click="unlinkDiscord" variant="destructive">
226-
{{ $t("pages.settings.account.discord.unlink_dialog.confirm") }}
227-
</AlertDialogAction>
228-
</AlertDialogFooter>
229-
</AlertDialogContent>
230-
</AlertDialog>
231140
</template>

‎components/settings/SettingsSideTabs.vue‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,5 @@ const showIndicator = computed(() => indicatorHeight.value > 0);
200200
</Button>
201201
</div>
202202
</div>
203-
204-
<div v-if="$slots.actions" class="mt-2 border-t border-border/50 pt-2">
205-
<slot name="actions" />
206-
</div>
207203
</nav>
208204
</template>

‎i18n/locales/ar_SA.json‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1770,6 +1770,9 @@
17701770
"matchmaking": "Matchmaking",
17711771
"update_success": "تم تحديث الملف الشخصي",
17721772
"discord": {
1773+
"title": "Discord",
1774+
"description": "انتقل تلقائيًا إلى القناة الصوتية لفريقك في المباريات",
1775+
"linked": "مرتبط",
17731776
"unlink": "افصل Discord",
17741777
"link": "اربط Discord",
17751778
"unlink_dialog": {

‎i18n/locales/da_DK.json‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1770,6 +1770,9 @@
17701770
"matchmaking": "Matchmaking",
17711771
"update_success": "Profil opdateret",
17721772
"discord": {
1773+
"title": "Discord",
1774+
"description": "Bliv flyttet til dit holds stemmekanal til kampe",
1775+
"linked": "Tilknyttet",
17731776
"unlink": "Fjern Discord",
17741777
"link": "Tilknyt Discord",
17751778
"unlink_dialog": {

‎i18n/locales/de_DE.json‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1770,6 +1770,9 @@
17701770
"matchmaking": "Matchmaking",
17711771
"update_success": "Profil aktualisiert",
17721772
"discord": {
1773+
"title": "Discord",
1774+
"description": "Werde für Matches in den Sprachkanal deines Teams verschoben",
1775+
"linked": "Verknüpft",
17731776
"unlink": "Discord trennen",
17741777
"link": "Discord verknüpfen",
17751778
"unlink_dialog": {

‎i18n/locales/en.json‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1770,6 +1770,9 @@
17701770
"matchmaking": "Matchmaking",
17711771
"update_success": "Updated Profile",
17721772
"discord": {
1773+
"title": "Discord",
1774+
"description": "Get moved into your team's voice channel for matches",
1775+
"linked": "Linked",
17731776
"unlink": "Unlink Discord",
17741777
"link": "Link Discord",
17751778
"unlink_dialog": {

‎i18n/locales/es_ES.json‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1770,6 +1770,9 @@
17701770
"matchmaking": "Matchmaking",
17711771
"update_success": "Perfil actualizado",
17721772
"discord": {
1773+
"title": "Discord",
1774+
"description": "Te movemos al canal de voz de tu equipo en las partidas",
1775+
"linked": "Vinculado",
17731776
"unlink": "Desvincular Discord",
17741777
"link": "Vincular Discord",
17751778
"unlink_dialog": {

‎i18n/locales/fr_FR.json‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1770,6 +1770,9 @@
17701770
"matchmaking": "Matchmaking",
17711771
"update_success": "Profil mis à jour",
17721772
"discord": {
1773+
"title": "Discord",
1774+
"description": "Soyez déplacé dans le salon vocal de votre équipe pendant les matchs",
1775+
"linked": "Lié",
17731776
"unlink": "Délier Discord",
17741777
"link": "Lier Discord",
17751778
"unlink_dialog": {

‎i18n/locales/it_IT.json‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1770,6 +1770,9 @@
17701770
"matchmaking": "Matchmaking",
17711771
"update_success": "Profilo aggiornato",
17721772
"discord": {
1773+
"title": "Discord",
1774+
"description": "Vieni spostato nel canale vocale della tua squadra durante le partite",
1775+
"linked": "Collegato",
17731776
"unlink": "Scollega Discord",
17741777
"link": "Collega Discord",
17751778
"unlink_dialog": {

0 commit comments

Comments
 (0)