impement and fix user settings
This commit is contained in:
@@ -36,24 +36,26 @@ class UserProfileController extends ControllerAbstract
|
||||
* Update user profile fields
|
||||
* Only editable fields can be updated. Provider-managed fields are automatically filtered out.
|
||||
*
|
||||
* @param array $profile Key-value pairs of profile fields to update
|
||||
* @param array $data Key-value pairs of profile fields to update
|
||||
*
|
||||
* @example request body:
|
||||
* {
|
||||
* "data": {
|
||||
* "name_given": "John",
|
||||
* "name_family": "Doe",
|
||||
* "phone": "+1234567890"
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @return JsonResponse Updated profile data
|
||||
*/
|
||||
#[AuthenticatedRoute('/user/profile', name: 'user.profile.update', methods: ['PUT', 'PATCH'])]
|
||||
public function update(array $profile = []): JsonResponse
|
||||
public function update(array $data): JsonResponse
|
||||
{
|
||||
$userId = $this->userIdentity->identifier();
|
||||
|
||||
// storeProfile automatically filters out provider-managed fields
|
||||
$this->userService->storeProfile($userId, $profile);
|
||||
$this->userService->storeProfile($userId, $data);
|
||||
|
||||
// Return updated profile
|
||||
$updatedProfile = $this->userService->fetchProfile($userId);
|
||||
|
||||
@@ -26,8 +26,8 @@ class UserSettingsController extends ControllerAbstract
|
||||
#[AuthenticatedRoute('/user/settings', name: 'user.settings.read', methods: ['GET'])]
|
||||
public function read(): JsonResponse
|
||||
{
|
||||
// Fetch all settings
|
||||
$settings = $this->userService->fetchSettings([]);
|
||||
// Fetch all settings (no filter)
|
||||
$settings = $this->userService->fetchSettings();
|
||||
|
||||
return new JsonResponse($settings, JsonResponse::HTTP_OK);
|
||||
}
|
||||
@@ -35,24 +35,26 @@ class UserSettingsController extends ControllerAbstract
|
||||
/**
|
||||
* Update user settings
|
||||
*
|
||||
* @param array $settings Key-value pairs of settings to update
|
||||
* @param array $data Key-value pairs of settings to update
|
||||
*
|
||||
* @example request body:
|
||||
* {
|
||||
* "data": {
|
||||
* "theme": "dark",
|
||||
* "language": "en",
|
||||
* "notifications": true
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @return JsonResponse Updated settings data
|
||||
*/
|
||||
#[AuthenticatedRoute('/user/settings', name: 'user.settings.update', methods: ['PUT', 'PATCH'])]
|
||||
public function update(array $settings = []): JsonResponse
|
||||
public function update(array $data): JsonResponse
|
||||
{
|
||||
$this->userService->storeSettings($settings);
|
||||
$this->userService->storeSettings($data);
|
||||
|
||||
// Return updated settings
|
||||
$updatedSettings = $this->userService->fetchSettings(array_keys($settings));
|
||||
$updatedSettings = $this->userService->fetchSettings(array_keys($data));
|
||||
|
||||
return new JsonResponse($updatedSettings, JsonResponse::HTTP_OK);
|
||||
}
|
||||
|
||||
@@ -197,7 +197,8 @@ class UserStore
|
||||
['$set' => $updates]
|
||||
);
|
||||
|
||||
return $result->getModifiedCount() > 0;
|
||||
// Return true if document was matched (exists), even if not modified
|
||||
return $result->getMatchedCount() > 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,4 +4,17 @@
|
||||
|
||||
<script setup lang="ts">
|
||||
import { RouterView } from 'vue-router';
|
||||
import { onMounted } from 'vue';
|
||||
import { useTheme } from 'vuetify';
|
||||
import { useLayoutStore } from '@KTXC/stores/layoutStore';
|
||||
|
||||
const theme = useTheme();
|
||||
const layoutStore = useLayoutStore();
|
||||
|
||||
// Apply saved theme on mount
|
||||
onMounted(() => {
|
||||
if (layoutStore.theme) {
|
||||
theme.global.name.value = layoutStore.theme;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -12,7 +12,7 @@ const userStore = useUserStore();
|
||||
const integrationStore = useIntegrationStore();
|
||||
const layoutStore = useLayoutStore();
|
||||
|
||||
const identityData = computed(() => userStore.user);
|
||||
const identityData = computed(() => userStore.auth);
|
||||
const profileMenuItems = computed(() => integrationStore.getItems('profile_menu'));
|
||||
|
||||
// Theme toggle
|
||||
@@ -20,7 +20,7 @@ const isDarkMode = computed(() => theme.global.name.value === 'dark');
|
||||
const toggleTheme = () => {
|
||||
const newTheme = theme.global.name.value === 'light' ? 'dark' : 'light';
|
||||
theme.global.name.value = newTheme;
|
||||
localStorage.setItem('theme', newTheme);
|
||||
layoutStore.setTheme(newTheme);
|
||||
};
|
||||
|
||||
// Navigate to settings
|
||||
@@ -45,7 +45,7 @@ const goToSettings = () => {
|
||||
<h6 class="text-h6 mb-0">
|
||||
{{ identityData?.label || 'User Name' }}
|
||||
</h6>
|
||||
<p class="text-caption mb-0">{{ identityData?.email || '' }}</p>
|
||||
<p class="text-caption mb-0">{{ userStore.getProfileField('email') || '' }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<v-divider />
|
||||
|
||||
@@ -36,7 +36,7 @@ export const userService = {
|
||||
profileUpdateTimer = null;
|
||||
|
||||
try {
|
||||
await fetchWrapper.put('/user/profile', updates);
|
||||
await fetchWrapper.put('/user/profile', { data: updates });
|
||||
resolve();
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
@@ -59,7 +59,7 @@ export const userService = {
|
||||
const updates = { ...pendingProfileUpdates, ...fields };
|
||||
pendingProfileUpdates = {};
|
||||
|
||||
return fetchWrapper.put('/user/profile', updates);
|
||||
return fetchWrapper.put('/user/profile', { data: updates });
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -74,7 +74,7 @@ export const userService = {
|
||||
if (Object.keys(pendingProfileUpdates).length > 0) {
|
||||
const updates = { ...pendingProfileUpdates };
|
||||
pendingProfileUpdates = {};
|
||||
return fetchWrapper.put('/user/profile', updates);
|
||||
return fetchWrapper.put('/user/profile', { data: updates });
|
||||
}
|
||||
},
|
||||
|
||||
@@ -99,7 +99,7 @@ export const userService = {
|
||||
settingsUpdateTimer = null;
|
||||
|
||||
try {
|
||||
await fetchWrapper.put('/user/settings', updates);
|
||||
await fetchWrapper.put('/user/settings', { data: updates });
|
||||
resolve();
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
@@ -122,7 +122,7 @@ export const userService = {
|
||||
const updates = { ...pendingSettingsUpdates, ...settings };
|
||||
pendingSettingsUpdates = {};
|
||||
|
||||
return fetchWrapper.put('/user/settings', updates);
|
||||
return fetchWrapper.put('/user/settings', { data: updates });
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -137,7 +137,7 @@ export const userService = {
|
||||
if (Object.keys(pendingSettingsUpdates).length > 0) {
|
||||
const updates = { ...pendingSettingsUpdates };
|
||||
pendingSettingsUpdates = {};
|
||||
return fetchWrapper.put('/user/settings', updates);
|
||||
return fetchWrapper.put('/user/settings', { data: updates });
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { ref } from 'vue';
|
||||
import { ref, watch } from 'vue';
|
||||
import { defineStore } from 'pinia';
|
||||
import config from '@KTXC/config';
|
||||
import { useUserStore } from './userStore';
|
||||
|
||||
export type MenuMode = 'apps' | 'settings';
|
||||
|
||||
@@ -8,14 +9,32 @@ export const useLayoutStore = defineStore('layout', () => {
|
||||
// Loading state
|
||||
const isLoading = ref(false);
|
||||
|
||||
// Sidebar state
|
||||
const sidebarDrawer = ref(config.Sidebar_drawer);
|
||||
const miniSidebar = ref(config.mini_sidebar);
|
||||
// Sidebar state - initialize from settings or config
|
||||
const userStore = useUserStore();
|
||||
const sidebarDrawer = ref(userStore.getSetting('sidebar_drawer') ?? config.Sidebar_drawer);
|
||||
const miniSidebar = ref(userStore.getSetting('mini_sidebar') ?? config.mini_sidebar);
|
||||
const menuMode = ref<MenuMode>('apps');
|
||||
|
||||
// Theme state
|
||||
const theme = ref(config.actTheme);
|
||||
const font = ref(config.fontTheme);
|
||||
// Theme state - initialize from settings or config
|
||||
const theme = ref(userStore.getSetting('theme') ?? config.actTheme);
|
||||
const font = ref(userStore.getSetting('font') ?? config.fontTheme);
|
||||
|
||||
// Watch and sync sidebar state to settings
|
||||
watch(sidebarDrawer, (value) => {
|
||||
userStore.setSetting('sidebar_drawer', value);
|
||||
});
|
||||
|
||||
watch(miniSidebar, (value) => {
|
||||
userStore.setSetting('mini_sidebar', value);
|
||||
});
|
||||
|
||||
watch(theme, (value) => {
|
||||
userStore.setSetting('theme', value);
|
||||
});
|
||||
|
||||
watch(font, (value) => {
|
||||
userStore.setSetting('font', value);
|
||||
});
|
||||
|
||||
// Actions
|
||||
function toggleSidebarDrawer() {
|
||||
|
||||
Reference in New Issue
Block a user