settingService->getSetting('usersettings.'.$userId.'.theme'); if (! $userTheme) { $userTheme = 'default'; } $userColorMode = $this->settingService->getSetting('usersettings.'.$userId.'.colorMode'); if (! $userColorMode) { $userColorMode = 'light'; } $userColorScheme = $this->settingService->getSetting('usersettings.'.$userId.'.colorScheme'); if (! $userColorScheme) { $userColorScheme = 'companyColors'; } $themeFont = $this->settingService->getSetting('usersettings.'.$userId.'.themeFont'); if (! $themeFont) { $themeFont = 'Roboto'; } $userDateFormat = $this->settingService->getSetting('usersettings.'.$userId.'.date_format'); $userTimeFormat = $this->settingService->getSetting('usersettings.'.$userId.'.time_format'); $timezone = $this->settingService->getSetting('usersettings.'.$userId.'.timezone'); if (! $timezone) { $timezone = date_default_timezone_get(); } $workdays = $this->settingService->getSetting('usersettings.'.$userId.'.workdays'); if (! $workdays) { $workdays = $this->getDefaultWorkdays(); } else { $workdays = safe_unserialize($workdays, []); } $daySchedule = $this->settingService->getSetting('usersettings.'.$userId.'.daySchedule'); if ($daySchedule) { $daySchedule = safe_unserialize($daySchedule, []); } else { $daySchedule = $this->getDefaultDaySchedule(); } return [ 'userTheme' => $userTheme, 'userColorMode' => $userColorMode, 'userColorScheme' => $userColorScheme, 'themeFont' => $themeFont, 'dateFormat' => $userDateFormat, 'timeFormat' => $userTimeFormat, 'dateTimeValues' => $this->getSupportedDateTimeFormats(), 'timezone' => $timezone, 'timezoneOptions' => timezone_identifiers_list(), 'availableColorSchemes' => $this->themeCore->getAvailableColorSchemes(), 'availableFonts' => $this->themeCore->getAvailableFonts(), 'fontTooltips' => $this->themeCore->fontTooltips, 'availableThemes' => $this->themeCore->getAll(), 'languageList' => $this->language->getLanguageList(), 'workdays' => $workdays, 'daySchedule' => $daySchedule, 'dayHourOptions' => $this->getDayHourOptions(), ]; } /** * getDefaultWorkdays - returns the default weekly working hours used when a * user has not yet configured their schedule. * * @return array */ public function getDefaultWorkdays(): array { return [ 1 => ['start' => '09:00', 'end' => '17:00'], 2 => ['start' => '09:00', 'end' => '17:00'], 3 => ['start' => '09:00', 'end' => '17:00'], 4 => ['start' => '09:00', 'end' => '17:00'], 5 => ['start' => '09:00', 'end' => '17:00'], ]; } /** * getDefaultDaySchedule - returns the default daily schedule used when a user * has not yet configured one. * * @return array */ public function getDefaultDaySchedule(): array { return [ 'wakeup' => 6, 'workStart' => 8, 'lunch' => 12, 'workEnd' => 16, 'bed' => 22, ]; } /** * getDayHourOptions - returns the catalog of selectable two-hour blocks used * when configuring the daily schedule. * * @return array */ public function getDayHourOptions(): array { return [ 0 => ['start' => '0:00', 'end' => '2:00'], 2 => ['start' => '2:00', 'end' => '4:00'], 4 => ['start' => '4:00', 'end' => '6:00'], 6 => ['start' => '6:00', 'end' => '8:00'], 8 => ['start' => '8:00', 'end' => '10:00'], 10 => ['start' => '10:00', 'end' => '12:00'], 12 => ['start' => '12:00', 'end' => '14:00'], 14 => ['start' => '14:00', 'end' => '16:00'], 16 => ['start' => '16:00', 'end' => '18:00'], 18 => ['start' => '18:00', 'end' => '20:00'], 20 => ['start' => '20:00', 'end' => '22:00'], 22 => ['start' => '22:00', 'end' => '0:00'], ]; } /** * getSupportedDateTimeFormats - returns the catalog of supported date and time * format options shown during onboarding. * * @return array{dates: array, times: array} */ public function getSupportedDateTimeFormats(): array { return [ 'dates' => [ $this->language->__('language.dateformat'), 'Y-m-d', 'D, d M y', 'l, d-M-y', 'd.m.Y', 'd/m/Y', 'd. F Y', 'm-d-Y', 'dmY', 'F d, Y', 'd F Y', ], 'times' => [ $this->language->__('language.timeformat'), 'H:i P', 'H:i O', 'H:i T', 'H:i:s', 'H:i', ], ]; } /** * saveAccount - first onboarding step: validates the chosen password, assembles * the user record from the submitted profile fields and persists it. * * The plaintext password is stored in the session (tempPassword) so the user can * be logged in automatically once onboarding completes, mirroring the original flow. * * @param array $userInvite the invited user record (resolved from the invite link) * @param string $name the full name as submitted (split into first/last name) * @param string $jobTitle the submitted job title * @param string $password the chosen password * @return string 'weak' if the password is not strong enough, 'saved' if the user was * persisted, 'error' if persistence failed * * @api */ public function saveAccount(array $userInvite, string $name, string $jobTitle, string $password): string { if (! $this->userService->checkPasswordStrength($password)) { return 'weak'; } $nameParts = explode(' ', $name); $userInvite['firstname'] = $nameParts[0]; $userInvite['lastname'] = $nameParts[1] ?? ''; $userInvite['jobTitle'] = $jobTitle; $userInvite['status'] = 'i'; $userInvite['user'] = $userInvite['username']; $userInvite['password'] = $password; session(['tempPassword' => $password]); if ($this->userService->editUser($userInvite, $userInvite['id'])) { return 'saved'; } return 'error'; } /** * saveThemeChoice - second onboarding step: persists the chosen theme and font, * activates them and dispatches the related onboarding events. * * @param array $userInvite the invited user record * @param string $theme the chosen theme * @param string $themeFont the chosen font * * @throws BindingResolutionException * * @api */ public function saveThemeChoice(array $userInvite, string $theme, string $themeFont): void { $postTheme = htmlentities($theme); $font = htmlentities($themeFont); $this->settingService->saveSetting('usersettings.'.$userInvite['id'].'.theme', $postTheme); $this->settingService->saveSetting('usersettings.'.$userInvite['id'].'.themeFont', $font); $this->themeCore->clearCache(); $this->themeCore->setActive($postTheme); $this->themeCore->setFont($font); $this->themeCore->clearCache(); self::dispatchEvent('onboarding_themechoice_'.$postTheme, [], self::EVENT_CONTEXT); self::dispatchEvent('onboarding_themechoice_'.$font, [], self::EVENT_CONTEXT); } /** * saveColorChoice - third onboarding step: persists the chosen color mode and * scheme, activates them and dispatches the related onboarding events. * * @param array $userInvite the invited user record * @param string $colorMode the chosen color mode * @param string $colorScheme the chosen color scheme * * @throws BindingResolutionException * * @api */ public function saveColorChoice(array $userInvite, string $colorMode, string $colorScheme): void { $postColorMode = htmlentities($colorMode); $postColorScheme = htmlentities($colorScheme); $this->settingService->saveSetting('usersettings.'.$userInvite['id'].'.colorMode', $postColorMode); $this->settingService->saveSetting('usersettings.'.$userInvite['id'].'.colorScheme', $postColorScheme); self::dispatchEvent('onboarding_colorchoice_'.$postColorMode, [], self::EVENT_CONTEXT); self::dispatchEvent('onboarding_colorchoice_'.$postColorScheme, [], self::EVENT_CONTEXT); $this->themeCore->clearCache(); $this->themeCore->setColorMode($postColorMode); $this->themeCore->setColorScheme($postColorScheme); $this->themeCore->clearCache(); } /** * saveSchedule - fourth onboarding step: assembles the day schedule from the * submitted values, dispatches the related onboarding events and persists it. * * @param array $userInvite the invited user record * @param string $workStart the submitted work start block * @param string $lunch the submitted lunch block * @param string $workEnd the submitted work end block * * @throws BindingResolutionException * * @api */ public function saveSchedule(array $userInvite, string $workStart, string $lunch, string $workEnd): void { $daySchedule = [ 'wakeup' => '', 'workStart' => $workStart, 'lunch' => $lunch, 'workEnd' => $workEnd, 'bed' => '', ]; self::dispatchEvent('onboarding_schedule_start_'.$daySchedule['workStart'], [], self::EVENT_CONTEXT); self::dispatchEvent('onboarding_schedule_lunch_'.$daySchedule['lunch'], [], self::EVENT_CONTEXT); self::dispatchEvent('onboarding_schedule_end_'.$daySchedule['workEnd'], [], self::EVENT_CONTEXT); $this->settingService->saveSetting('usersettings.'.$userInvite['id'].'.daySchedule', serialize($daySchedule)); } /** * completeOnboarding - final onboarding step: activates the user, dispatches the * onboarding-finished and signup-success events, then logs the user in using the * temporary password captured during account setup. * * @param array $userInvite the invited user record * @return bool true if the user was successfully logged in, false otherwise * * @throws BindingResolutionException * * @api */ public function completeOnboarding(array $userInvite): bool { $userInvite['status'] = 'A'; $userInvite['password'] = ''; $userInvite['user'] = $userInvite['username']; $this->userService->editUser($userInvite, $userInvite['id']); self::dispatchEvent('onboarding_finished', [], self::EVENT_CONTEXT); $loggedIn = $this->authService->login($userInvite['username'], session('tempPassword')); session()->forget('tempPassword'); self::dispatch_event('userSignUpSuccess', ['user' => $userInvite], self::EVENT_CONTEXT); return $loggedIn; } }