Skip to content

Commit

Permalink
Decompose LoginPage
Browse files Browse the repository at this point in the history
  • Loading branch information
jacobtylerwalls committed Aug 9, 2024
1 parent f0ef633 commit 6b199f6
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 85 deletions.
7 changes: 6 additions & 1 deletion arches_lingo/src/arches_lingo/App.vue
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
<script setup lang="ts">
import { ref } from "vue";
import { provide, ref } from "vue";
import Toast from "primevue/toast";
import { userKey } from "@/arches_lingo/constants.ts";
import HomePage from "@/arches_lingo/components/HomePage.vue";
import LoginPage from "@/arches_lingo/components/LoginPage.vue";
import type { User } from "@/arches_lingo/types";
const user = ref<User | null>(null);
const setUser = (userToSet: User | null) => {
user.value = userToSet;
};
provide(userKey, { user, setUser });
</script>

<template>
Expand Down
7 changes: 4 additions & 3 deletions arches_lingo/src/arches_lingo/components/HomePage.vue
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
<script setup lang="ts">
import { computed } from "vue";
import { computed, inject } from "vue";
import { useGettext } from "vue3-gettext";
import { useToast } from "primevue/usetoast";
import Button from "primevue/button";
import { DEFAULT_ERROR_TOAST_LIFE, ERROR } from "@/arches_lingo/constants.ts";
import { logout } from "@/arches_lingo/api.ts";
import { userKey } from "@/arches_lingo/constants.ts";
import type { User } from "@/arches_lingo/types";
import type { UserRefAndSetter } from "@/arches_lingo/types";
const user = defineModel<User | null>({ required: true });
const { user } = inject(userKey) as UserRefAndSetter;
const { $gettext } = useGettext();
const toast = useToast();
Expand Down
78 changes: 78 additions & 0 deletions arches_lingo/src/arches_lingo/components/LoginForm.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<script setup lang="ts">
import { inject, ref } from "vue";
import { useGettext } from "vue3-gettext";
import { useToast } from "primevue/usetoast";
import InputText from "primevue/inputtext";
import Button from "primevue/button";
import { login } from "@/arches_lingo/api.ts";
import {
DEFAULT_ERROR_TOAST_LIFE,
ERROR,
userKey,
} from "@/arches_lingo/constants.ts";
import type { UserRefAndSetter } from "@/arches_lingo/types";
const { $gettext } = useGettext();
const toast = useToast();
const { setUser } = inject(userKey) as UserRefAndSetter;
const username = ref();
const password = ref();
const submit = async () => {
try {
const userToSet = await login(username.value, password.value);
setUser(userToSet);
} catch (error) {
toast.add({
severity: ERROR,
life: DEFAULT_ERROR_TOAST_LIFE,
summary: $gettext("Sign in failed."),
detail: error instanceof Error ? error.message : undefined,
});
}
};
</script>

<template>
<form>
<h1>{{ $gettext("LINGO") }}</h1>
<h2>{{ $gettext("Vocabulary management powered by Arches.") }}</h2>
<InputText
v-model="username"
:placeholder="$gettext('Username')"
:aria-label="$gettext('Username')"
autocomplete="username"
/>
<InputText
v-model="password"
:placeholder="$gettext('Password')"
:aria-label="$gettext('Password')"
type="password"
autocomplete="password"
@keyup.enter="submit"
/>

<Button
type="button"
:label="$gettext('Sign In')"
@click="submit"
/>
</form>
</template>

<style scoped>
form {
display: flex;
flex-direction: column;
gap: 1rem;
width: 30%;
}
input {
width: 100%;
}
</style>
23 changes: 23 additions & 0 deletions arches_lingo/src/arches_lingo/components/LoginLinks.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<script setup lang="ts">
import arches from "arches";
import { useGettext } from "vue3-gettext";
import Button from "primevue/button";
const { $gettext } = useGettext();
</script>

<template>
<div style="display: flex; justify-content: space-between; width: 30%">
<Button
as="a"
:label="$gettext('Register')"
:href="arches.urls.signup"
/>
<Button
as="a"
:label="$gettext('Multi-factor login')"
:href="arches.urls.auth"
/>
</div>
</template>
85 changes: 4 additions & 81 deletions arches_lingo/src/arches_lingo/components/LoginPage.vue
Original file line number Diff line number Diff line change
@@ -1,92 +1,15 @@
<script setup lang="ts">
import arches from "arches";
import { ref } from "vue";
import { useGettext } from "vue3-gettext";
import { useToast } from "primevue/usetoast";
import InputText from "primevue/inputtext";
import Button from "primevue/button";
import { DEFAULT_ERROR_TOAST_LIFE, ERROR } from "@/arches_lingo/constants.ts";
import { login } from "@/arches_lingo/api.ts";
import type { User } from "@/arches_lingo/types";
const { $gettext } = useGettext();
const toast = useToast();
const user = defineModel<User | null>({ required: true });
const username = ref();
const password = ref();
const submit = async () => {
try {
user.value = await login(username.value, password.value);
} catch (error) {
toast.add({
severity: ERROR,
life: DEFAULT_ERROR_TOAST_LIFE,
summary: $gettext("Sign in failed."),
detail: error instanceof Error ? error.message : undefined,
});
}
};
import LoginForm from "@/arches_lingo/components/LoginForm.vue";
import LoginLinks from "@/arches_lingo/components/LoginLinks.vue";
</script>

<template>
<div style="margin: 5%">
<form>
<h1>{{ $gettext("LINGO") }}</h1>
<h2>{{ $gettext("Vocabulary management powered by Arches.") }}</h2>
<InputText
v-model="username"
:placeholder="$gettext('Username')"
:aria-label="$gettext('Username')"
autocomplete="username"
/>
<InputText
v-model="password"
:placeholder="$gettext('Password')"
:aria-label="$gettext('Password')"
type="password"
autocomplete="password"
@keyup.enter="submit"
/>

<Button
type="button"
:label="$gettext('Sign In')"
@click="submit"
/>
</form>
<LoginForm />
<div
class="spacer"
style="height: 10rem"
></div>
<div style="display: flex; justify-content: space-between; width: 30%">
<Button
as="a"
:label="$gettext('Register')"
:href="arches.urls.signup"
/>
<Button
as="a"
:label="$gettext('Multi-factor login')"
:href="arches.urls.auth"
/>
</div>
<LoginLinks />
</div>
</template>

<style scoped>
form {
display: flex;
flex-direction: column;
gap: 1rem;
width: 30%;
}
input {
width: 100%;
}
</style>
5 changes: 5 additions & 0 deletions arches_lingo/src/arches_lingo/constants.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
import type { InjectionKey } from "vue";
import type { UserRefAndSetter } from "@/arches_lingo/types";

export const ERROR = "error";
export const DEFAULT_ERROR_TOAST_LIFE = 8000;

export const userKey = Symbol() as InjectionKey<UserRefAndSetter>;
8 changes: 8 additions & 0 deletions arches_lingo/src/arches_lingo/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
import type { Ref } from "vue";

export interface User {
first_name: string;
last_name: string;
username: string;
}

// Prop injection types
export interface UserRefAndSetter {
user: Ref<User | null>;
setUser: (userToSet: User | null) => void;
}

0 comments on commit 6b199f6

Please sign in to comment.