Skip to content

Commit

Permalink
Maintenance: Desktop view - App theme defaulted to light mode on init…
Browse files Browse the repository at this point in the history
…ial setup
  • Loading branch information
vBenTec committed May 24, 2024
1 parent 152e336 commit 9c49a21
Show file tree
Hide file tree
Showing 15 changed files with 363 additions and 451 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import type { DateTimeContext } from '#shared/components/Form/fields/FieldDate/t
import { useDateTime } from '#shared/components/Form/fields/FieldDate/useDateTime.ts'
import { EnumTextDirection } from '#shared/graphql/types.ts'
import { i18n } from '#shared/i18n.ts'
import { useAppTheme } from '#shared/stores/theme.ts'
import { useThemeStore } from '#desktop/stores/theme.ts'
import '@vuepic/vue-datepicker/dist/main.css'
interface Props {
Expand Down Expand Up @@ -59,9 +60,9 @@ const inputIcon = computed(() => {
const picker = ref<DatePickerInstance>()
const { theme } = storeToRefs(useAppTheme())
const { currentTheme } = storeToRefs(useThemeStore())
const dark = computed(() => theme.value === 'dark')
const dark = computed(() => currentTheme.value === 'dark')
</script>

<template>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
<!-- Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/ -->

<script setup lang="ts">
import { ref } from 'vue'
import { storeToRefs } from 'pinia'
import { computed, ref } from 'vue'
import CommonPopoverMenuItem, {
type Props,
} from '#desktop/components/CommonPopover/CommonPopoverMenuItem.vue'
import ThemeSwitch from '#desktop/components/ThemeSwitch/ThemeSwitch.vue'
import type { ThemeSwitchInstance } from '#desktop/components/ThemeSwitch/types.ts'
import { useThemeUpdate } from '#desktop/pages/personal-setting/composables/useThemeUpdate.ts'
import { useThemeStore } from '#desktop/stores/theme.ts'
defineProps<Props>()
Expand All @@ -18,7 +19,14 @@ const cycleThemeSwitchValue = () => {
themeSwitch.value?.cycleValue()
}
const { currentTheme } = useThemeUpdate()
const themeStore = useThemeStore()
const { updateTheme } = themeStore
const { currentTheme } = storeToRefs(themeStore)
const modelTheme = computed({
get: () => currentTheme.value,
set: (theme) => updateTheme(theme),
})
</script>

<template>
Expand All @@ -29,7 +37,7 @@ const { currentTheme } = useThemeUpdate()
<div class="flex items-center px-2">
<ThemeSwitch
ref="themeSwitch"
v-model="currentTheme"
v-model="modelTheme"
class="hover:outline-blue-300 focus:outline-blue-600 hover:focus:outline-blue-600 dark:hover:outline-blue-950 dark:focus:outline-blue-900 dark:hover:focus:outline-blue-900"
size="small"
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ import { useSessionStore } from '#shared/stores/session.ts'

import AvatarMenuAppearanceItem from '../AvatarMenuAppearanceItem.vue'

describe('avatar menu apperance item', () => {
beforeEach(() => {
describe('avatar menu appearance item', () => {
it('renders menu item with switcher', async () => {
mockUserCurrent({
lastname: 'Doe',
firstname: 'John',
preferences: {},
preferences: {
theme: EnumAppearanceTheme.Dark,
},
})
})

it('renders menu item with switcher', async () => {
const view = renderComponent(AvatarMenuAppearanceItem, {
props: {
label: 'Appearance',
Expand All @@ -29,14 +29,14 @@ describe('avatar menu apperance item', () => {
expect(view.getByText('Appearance')).toBeInTheDocument()
const appearanceSwitch = view.getByRole('checkbox', { name: 'Dark Mode' })

expect(appearanceSwitch).toBePartiallyChecked()
expect(appearanceSwitch).toBeChecked()

await view.events.click(appearanceSwitch)

expect(appearanceSwitch).toBeChecked()
expect(appearanceSwitch).not.toBeChecked()

const session = useSessionStore()

expect(session.user?.preferences?.theme).toBe(EnumAppearanceTheme.Dark)
expect(session.user?.preferences?.theme).toBe(EnumAppearanceTheme.Light)
})
})
4 changes: 2 additions & 2 deletions app/frontend/apps/desktop/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import { useAuthenticationStore } from '#shared/stores/authentication.ts'
import initializeStore from '#shared/stores/index.ts'
import { useLocaleStore } from '#shared/stores/locale.ts'
import { useSessionStore } from '#shared/stores/session.ts'
import { useAppTheme } from '#shared/stores/theme.ts'

import { twoFactorConfigurationPluginLookup } from '#desktop/entities/two-factor-configuration/plugins/index.ts'
import { initializeForm, initializeFormFields } from '#desktop/form/index.ts'
Expand All @@ -23,6 +22,7 @@ import { initializeGlobalComponentStyles } from '#desktop/initializer/initialize
import { ensureAfterAuth } from '#desktop/pages/authentication/after-auth/composable/useAfterAuthPlugins.ts'
import initializeRouter from '#desktop/router/index.ts'
import initializeApolloClient from '#desktop/server/apollo/index.ts'
import { useThemeStore } from '#desktop/stores/theme.ts'

import App from './AppDesktop.vue'

Expand Down Expand Up @@ -72,7 +72,7 @@ export const mountApp = async () => {
}

// sync theme so the store is initialized and user (if exists) and DOM have the same value
useAppTheme().syncTheme()
useThemeStore().syncTheme()

if (VITE_TEST_MODE) {
await import('#shared/initializer/initializeFakeTimer.ts')
Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,74 @@
// Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/

import { visitView } from '#tests/support/components/visitView.ts'
import { mockUserCurrent } from '#tests/support/mock-userCurrent.ts'

import { waitForUserCurrentAppearanceMutationCalls } from '../graphql/mutations/userCurrentAppearance.mocks.ts'
import { EnumAppearanceTheme } from '#shared/graphql/types.ts'

import { waitForUserCurrentAppearanceMutationCalls } from '#desktop/pages/personal-setting/graphql/mutations/userCurrentAppearance.mocks.ts'

describe('appearance page', () => {
it('should have dark theme set', async () => {
mockUserCurrent({
preferences: {
theme: EnumAppearanceTheme.Dark,
},
})

const view = await visitView('/personal-setting/appearance')

expect(view.getByRole('radio', { checked: true })).toHaveTextContent('dark')
})

it('should have light theme set', async () => {
mockUserCurrent({
preferences: {
theme: EnumAppearanceTheme.Light,
},
})

const view = await visitView('/personal-setting/appearance')

expect(view.getByRole('radio', { checked: true })).toHaveTextContent(
'light',
)
})

it('update appearance to dark', async () => {
mockUserCurrent({
preferences: {
theme: EnumAppearanceTheme.Light,
},
})
const view = await visitView('/personal-setting/appearance')

expect(view.getByLabelText('Light')).toBeChecked()

const darkMode = view.getByText('Dark')
const lightMode = view.getByText('Light')
const syncWithComputer = view.getByText('Sync with computer')

await view.events.click(darkMode)

expect(view.getByLabelText('Dark')).toBeChecked()

const calls = await waitForUserCurrentAppearanceMutationCalls()

expect(calls.at(-1)?.variables).toEqual({ theme: 'dark' })
expect(window.matchMedia('(prefers-color-scheme: light)').matches).toBe(
false,
)

await view.events.click(lightMode)
await vi.waitUntil(() => calls.length === 2)

expect(calls.at(-1)?.variables).toEqual({ theme: 'light' })
expect(window.matchMedia('(prefers-color-scheme: dark)').matches).toBe(
false,
)

await view.events.click(syncWithComputer)

expect(view.getByLabelText('Sync with computer')).toBeChecked()
})
})

This file was deleted.

This file was deleted.

Loading

0 comments on commit 9c49a21

Please sign in to comment.