diff --git a/src/components/home/TheNavigation.vue b/src/components/home/TheNavigation.vue index 5569a1cca..77d0b6e0e 100644 --- a/src/components/home/TheNavigation.vue +++ b/src/components/home/TheNavigation.vue @@ -44,8 +44,8 @@ variant="secondary" :shadow="false" > - - {{ userInfo.name !== '' ? userInfo.name : userInfo.username }} + + {{ authStore.userDisplayName }} @@ -80,7 +80,7 @@ {{ $t('about.title') }} {{ $t('user.auth.logout') }} @@ -117,8 +117,6 @@ const canWriteCurrentList = computed(() => baseStore.currentList.maxRight > Righ const menuActive = computed(() => baseStore.menuActive) const authStore = useAuthStore() -const userInfo = computed(() => authStore.info) -const userAvatar = computed(() => authStore.avatarUrl) const configStore = useConfigStore() const imprintUrl = computed(() => configStore.legal.imprintUrl) @@ -136,10 +134,6 @@ onMounted(async () => { listTitle.value.style.setProperty('--nav-username-width', `${usernameWidth}px`) }) -function logout() { - authStore.logout() -} - function openQuickActions() { baseStore.setQuickActionsActive(true) } diff --git a/src/components/tasks/partials/editAssignees.vue b/src/components/tasks/partials/editAssignees.vue index 29315269f..78a1a3577 100644 --- a/src/components/tasks/partials/editAssignees.vue +++ b/src/components/tasks/partials/editAssignees.vue @@ -41,6 +41,7 @@ import {success} from '@/message' import {useTaskStore} from '@/stores/tasks' import type {IUser} from '@/modelTypes/IUser' +import { getDisplayName } from '@/models/user' const props = defineProps({ taskId: { @@ -65,7 +66,7 @@ const taskStore = useTaskStore() const {t} = useI18n({useScope: 'global'}) const listUserService = shallowReactive(new ListUserService()) -const foundUsers = ref([]) +const foundUsers = ref([]) const assignees = ref([]) let isAdding = false @@ -114,13 +115,14 @@ async function findUser(query: string) { return } - const response = await listUserService.getAll({listId: props.listId}, {s: query}) + const response = await listUserService.getAll({listId: props.listId}, {s: query}) as IUser[] // Filter the results to not include users who are already assigned - foundUsers.value = response.filter(({id}) => !includesById(assignees.value, id)) + foundUsers.value = response + .filter(({id}) => !includesById(assignees.value, id)) .map(u => { // Users may not have a display name set, so we fall back on the username in that case - u.name = u.name === '' ? u.username : u.name + u.name = getDisplayName(u) return u }) } diff --git a/src/composables/useDateTimeSalutation.test.ts b/src/composables/useDateTimeSalutation.test.ts deleted file mode 100644 index ecd48024f..000000000 --- a/src/composables/useDateTimeSalutation.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -import {describe, it, expect} from 'vitest' -import {hourToSalutation} from './useDateTimeSalutation' - -const dateWithHour = (hours: number): Date => { - const date = new Date() - date.setHours(hours) - return date -} - -describe('Salutation', () => { - it('shows the right salutation in the night', () => { - const salutation = hourToSalutation(dateWithHour(4)) - expect(salutation).toBe('home.welcomeNight') - }) - it('shows the right salutation in the morning', () => { - const salutation = hourToSalutation(dateWithHour(8)) - expect(salutation).toBe('home.welcomeMorning') - }) - it('shows the right salutation in the day', () => { - const salutation = hourToSalutation(dateWithHour(13)) - expect(salutation).toBe('home.welcomeDay') - }) - it('shows the right salutation in the night', () => { - const salutation = hourToSalutation(dateWithHour(20)) - expect(salutation).toBe('home.welcomeEvening') - }) - it('shows the right salutation in the night again', () => { - const salutation = hourToSalutation(dateWithHour(23)) - expect(salutation).toBe('home.welcomeNight') - }) -}) \ No newline at end of file diff --git a/src/composables/useDateTimeSalutation.ts b/src/composables/useDateTimeSalutation.ts deleted file mode 100644 index 001c5d80c..000000000 --- a/src/composables/useDateTimeSalutation.ts +++ /dev/null @@ -1,31 +0,0 @@ -import {computed} from 'vue' -import {useNow} from '@vueuse/core' - -const TRANSLATION_KEY_PREFIX = 'home.welcome' - -export function hourToSalutation(now: Date) { - const hours = now.getHours() - - if (hours < 5) { - return `${TRANSLATION_KEY_PREFIX}Night` - } - - if (hours < 11) { - return `${TRANSLATION_KEY_PREFIX}Morning` - } - - if (hours < 18) { - return `${TRANSLATION_KEY_PREFIX}Day` - } - - if (hours < 23) { - return `${TRANSLATION_KEY_PREFIX}Evening` - } - - return `${TRANSLATION_KEY_PREFIX}Night` -} - -export function useDateTimeSalutation() { - const now = useNow() - return computed(() => hourToSalutation(now.value)) -} \ No newline at end of file diff --git a/src/composables/useDaytimeSalutation.ts b/src/composables/useDaytimeSalutation.ts new file mode 100644 index 000000000..c60b9b162 --- /dev/null +++ b/src/composables/useDaytimeSalutation.ts @@ -0,0 +1,26 @@ +import {computed} from 'vue' +import {useI18n} from 'vue-i18n' +import {useNow} from '@vueuse/core' + +import {useAuthStore} from '@/stores/auth' +import {hourToDaytime} from '@/helpers/hourToDaytime' + +export type Daytime = 'night' | 'morning' | 'day' | 'evening' + +export function useDaytimeSalutation() { + const {t} = useI18n({useScope: 'global'}) + const now = useNow() + const authStore = useAuthStore() + + const name = computed(() => authStore.userDisplayName) + const daytime = computed(() => hourToDaytime(now.value)) + + const salutations = { + 'night': () => t('home.welcomeNight', {username: name.value}), + 'morning': () => t('home.welcomeMorning', {username: name.value}), + 'day': () => t('home.welcomeDay', {username: name.value}), + 'evening': () => t('home.welcomeEvening', {username: name.value}), + } as Record string> + + return computed(() => name.value ? salutations[daytime.value]() : undefined) +} \ No newline at end of file diff --git a/src/helpers/hourToDaytime.test.ts b/src/helpers/hourToDaytime.test.ts new file mode 100644 index 000000000..9f7bbb703 --- /dev/null +++ b/src/helpers/hourToDaytime.test.ts @@ -0,0 +1,31 @@ +import {describe, it, expect} from 'vitest' +import {hourToDaytime} from "./hourToDaytime" + +function dateWithHour(hours: number): Date { + const newDate = new Date() + newDate.setHours(hours, 0, 0,0 ) + return newDate +} + +describe('Salutation', () => { + it('shows the right salutation in the night', () => { + const salutation = hourToDaytime(dateWithHour(4)) + expect(salutation).toBe('night') + }) + it('shows the right salutation in the morning', () => { + const salutation = hourToDaytime(dateWithHour(8)) + expect(salutation).toBe('morning') + }) + it('shows the right salutation in the day', () => { + const salutation = hourToDaytime(dateWithHour(13)) + expect(salutation).toBe('day') + }) + it('shows the right salutation in the night', () => { + const salutation = hourToDaytime(dateWithHour(20)) + expect(salutation).toBe('evening') + }) + it('shows the right salutation in the night again', () => { + const salutation = hourToDaytime(dateWithHour(23)) + expect(salutation).toBe('night') + }) +}) \ No newline at end of file diff --git a/src/helpers/hourToDaytime.ts b/src/helpers/hourToDaytime.ts new file mode 100644 index 000000000..ea1430e48 --- /dev/null +++ b/src/helpers/hourToDaytime.ts @@ -0,0 +1,14 @@ +import type { Daytime } from '@/composables/useDaytimeSalutation' + +export function hourToDaytime(now: Date): Daytime { + const hours = now.getHours() + + const daytimeMap = { + night: hours < 5 || hours > 23, + morning: hours < 11, + day: hours < 18, + evening: hours < 23, + } as Record + + return (Object.keys(daytimeMap) as Daytime[]).find((daytime) => daytimeMap[daytime]) || 'night' +} diff --git a/src/i18n/lang/en.json b/src/i18n/lang/en.json index a4712a277..c7320af8b 100644 --- a/src/i18n/lang/en.json +++ b/src/i18n/lang/en.json @@ -1,9 +1,9 @@ { "home": { - "welcomeNight": "Good Night {username}", - "welcomeMorning": "Good Morning {username}", - "welcomeDay": "Hi {username}", - "welcomeEvening": "Good Evening {username}", + "welcomeNight": "Good Night {username}!", + "welcomeMorning": "Good Morning {username}!", + "welcomeDay": "Hi {username}!", + "welcomeEvening": "Good Evening {username}!", "lastViewed": "Last viewed", "list": { "newText": "You can create a new list for your new tasks:", diff --git a/src/modelTypes/IUser.ts b/src/modelTypes/IUser.ts index 01b64a927..45d46298c 100644 --- a/src/modelTypes/IUser.ts +++ b/src/modelTypes/IUser.ts @@ -7,7 +7,7 @@ export const AUTH_TYPES = { 'LINK_SHARE': 2, } as const -type AuthType = typeof AUTH_TYPES[keyof typeof AUTH_TYPES] +export type AuthType = typeof AUTH_TYPES[keyof typeof AUTH_TYPES] export interface IUser extends IAbstract { id: number diff --git a/src/stores/auth.ts b/src/stores/auth.ts index ace2e4d51..b9c16bad5 100644 --- a/src/stores/auth.ts +++ b/src/stores/auth.ts @@ -3,7 +3,7 @@ import {defineStore, acceptHMRUpdate} from 'pinia' import {HTTPFactory, AuthenticatedHTTPFactory} from '@/http-common' import {i18n, getCurrentLanguage, saveLanguage} from '@/i18n' import {objectToSnakeCase} from '@/helpers/case' -import UserModel, { getAvatarUrl } from '@/models/user' +import UserModel, { getAvatarUrl, getDisplayName } from '@/models/user' import UserSettingsService from '@/services/userSettings' import {getToken, refreshToken, removeToken, saveToken} from '@/helpers/auth' import {setModuleLoading} from '@/stores/helper' @@ -54,6 +54,9 @@ export const useAuthStore = defineStore('auth', { state.info.type === AUTH_TYPES.LINK_SHARE ) }, + userDisplayName(state) { + return state.info ? getDisplayName(state.info) : undefined + }, }, actions: { setIsLoading(isLoading: boolean) { diff --git a/src/views/Home.vue b/src/views/Home.vue index 5ab42bbcb..73b53ca9b 100644 --- a/src/views/Home.vue +++ b/src/views/Home.vue @@ -1,8 +1,7 @@