Skip to content

Commit f943ce7

Browse files
authored
Merge pull request #30 from codebridger/CU-86ewfyjet_Implement-User-Time-Zone-Support_Navid-Shad
Cu 86ewfyjet implement user time zone support navid shad
2 parents 531f124 + bb7d155 commit f943ce7

15 files changed

Lines changed: 594 additions & 279 deletions

File tree

frontend/components/Leitner/LeitnerSettings.vue

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
$t('smart_review.next_session') }}</p>
2323
<h3 class="text-2xl font-black text-gray-900 dark:text-white">{{ localSettings.reviewHour }}:00</h3>
2424
<p class="text-xs text-gray-500">{{ localSettings.reviewInterval === 1 ? $t('smart_review.daily') :
25-
$t('smart_review.every_days_reminder', { days: localSettings.reviewInterval }) }}</p>
25+
$t('smart_review.every_days_reminder', { days: localSettings.reviewInterval }) }} ({{
26+
profileStore.userDetail?.timeZone || 'UTC' }})</p>
2627
</div>
2728
<div class="absolute -right-4 -bottom-4 opacity-10 pointer-events-none">
2829
<Icon name="IconClock" class="!w-24 !h-24 text-success" />

frontend/locales/en.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,10 @@
186186
"reset-password": "Reset Password",
187187
"uploading": "Uploading...",
188188
"profile-updated": "Profile updated successfully",
189-
"profile-update-failed": "Failed to update profile"
189+
"profile-update-failed": "Failed to update profile",
190+
"timezone": "Timezone",
191+
"select_timezone": "Select Timezone",
192+
"timezone_desc": "Select your local timezone so reviews appear at the correct time."
190193
},
191194
"billing": {
192195
"billing": "Billing",

frontend/pages/auth/login.vue

Lines changed: 84 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -3,50 +3,44 @@
33
<div class="absolute inset-0">
44
<img :src="backgroundImage" alt="background gradient" class="h-full w-full object-cover" />
55
</div>
6-
<div
7-
:class="`bg-[url(${mapBackgroundImage})]`"
8-
class="relative flex min-h-screen items-center justify-center bg-cover bg-center bg-no-repeat px-6 py-10 dark:bg-[#060818] sm:px-16"
9-
>
10-
<img :src="comingSoonObject1" alt="coming soon object 1" class="absolute left-0 top-1/2 h-full max-h-[893px] -translate-y-1/2" />
11-
<img :src="comingSoonObject2" alt="coming soon object 2" class="absolute left-24 top-0 h-40 md:left-[30%]" />
6+
<div :class="`bg-[url(${mapBackgroundImage})]`"
7+
class="relative flex min-h-screen items-center justify-center bg-cover bg-center bg-no-repeat px-6 py-10 dark:bg-[#060818] sm:px-16">
8+
<img :src="comingSoonObject1" alt="coming soon object 1"
9+
class="absolute left-0 top-1/2 h-full max-h-[893px] -translate-y-1/2" />
10+
<img :src="comingSoonObject2" alt="coming soon object 2"
11+
class="absolute left-24 top-0 h-40 md:left-[30%]" />
1212
<img :src="comingSoonObject3" alt="coming soon object 3" class="absolute right-0 top-0 h-[300px]" />
1313
<img :src="polygonObject" alt="polygon object" class="absolute bottom-0 end-[28%]" />
1414
<div
15-
class="relative flex w-full max-w-[1502px] flex-col justify-between overflow-hidden rounded-md bg-white/60 backdrop-blur-lg dark:bg-black/50 lg:min-h-[700px] lg:flex-row lg:gap-10 xl:gap-0"
16-
>
15+
class="relative flex w-full max-w-[1502px] flex-col justify-between overflow-hidden rounded-md bg-white/60 backdrop-blur-lg dark:bg-black/50 lg:min-h-[700px] lg:flex-row lg:gap-10 xl:gap-0">
1716
<div
18-
class="relative hidden w-full items-center justify-center bg-[#220660] p-5 lg:inline-flex lg:max-w-[835px] xl:-ms-28 ltr:xl:skew-x-[14deg] rtl:xl:skew-x-[-14deg]"
19-
>
17+
class="relative hidden w-full items-center justify-center bg-[#220660] p-5 lg:inline-flex lg:max-w-[835px] xl:-ms-28 ltr:xl:skew-x-[14deg] rtl:xl:skew-x-[-14deg]">
2018
<div
21-
class="absolute inset-y-0 w-8 from-primary/10 via-transparent to-transparent xl:w-16 ltr:-right-10 ltr:bg-gradient-to-r ltr:xl:-right-20 rtl:-left-10 rtl:bg-gradient-to-l rtl:xl:-left-20"
22-
></div>
19+
class="absolute inset-y-0 w-8 from-primary/10 via-transparent to-transparent xl:w-16 ltr:-right-10 ltr:bg-gradient-to-r ltr:xl:-right-20 rtl:-left-10 rtl:bg-gradient-to-l rtl:xl:-left-20">
20+
</div>
2321
<div class="ltr:xl:-skew-x-[14deg] rtl:xl:skew-x-[14deg]">
2422
<div class="w-full">
2523
<img :src="loginCover" alt="Cover Image" class="w-full" />
2624
</div>
2725
</div>
2826
</div>
29-
<div class="relative flex w-full flex-col items-center justify-center gap-6 px-4 pb-16 pt-6 sm:px-6 lg:max-w-[667px]">
27+
<div
28+
class="relative flex w-full flex-col items-center justify-center gap-6 px-4 pb-16 pt-6 sm:px-6 lg:max-w-[667px]">
3029
<div class="w-full max-w-[440px] lg:mt-16">
3130
<div class="mb-16 lg:mb-40">
32-
<h1 class="text-3xl font-extrabold uppercase !leading-snug text-primary md:text-4xl">{{ t('auth.signin') }}</h1>
31+
<h1 class="text-3xl font-extrabold uppercase !leading-snug text-primary md:text-4xl">{{
32+
t('auth.signin') }}</h1>
3333
<p class="text-base font-bold leading-normal text-white-dark">
3434
Use one of your social accounts to {{ t('auth.signin') }} / {{ t('auth.signup') }}.
3535
</p>
3636
</div>
3737
<form class="space-y-5 dark:text-white" @submit.prevent="router.push('/')">
38-
<Button
39-
@click="triggerGoogleLoginProcess"
40-
color="gradient"
41-
shadow
42-
uppercase
43-
block
44-
iconName="IconGoogle"
45-
:label="t('auth.signin_with_google')"
46-
/>
38+
<Button @click="triggerGoogleLoginProcess" color="gradient" shadow uppercase block
39+
iconName="IconGoogle" :label="t('auth.signin_with_google')" />
4740
</form>
4841
<div class="relative my-7 text-center md:mb-9">
49-
<span class="absolute inset-x-0 top-1/2 h-px w-full -translate-y-1/2 bg-white-light dark:bg-white-dark"></span>
42+
<span
43+
class="absolute inset-x-0 top-1/2 h-px w-full -translate-y-1/2 bg-white-light dark:bg-white-dark"></span>
5044
</div>
5145
<div class="text-center dark:text-white">
5246
Don't have an account ?
@@ -60,66 +54,71 @@
6054
</template>
6155

6256
<script lang="ts" setup>
63-
// import { useAppStore } from '@/stores/index';
64-
import { useRouter, useRoute } from 'vue-router';
65-
import { computed, onMounted } from 'vue';
66-
import { Button } from '@codebridger/lib-vue-components/elements.ts';
67-
import { authentication } from '@modular-rest/client';
68-
69-
const { t } = useI18n();
70-
71-
useHead({ title: t('auth.login_page') });
72-
73-
const router = useRouter();
74-
const route = useRoute();
75-
76-
definePageMeta({
77-
layout: 'auth',
78-
});
79-
80-
// const store = useAppStore();
81-
// const { setLocale } = useI18n();
82-
83-
// multi language
84-
// const changeLanguage = (item: any) => {
85-
// appSetting.toggleLanguage(item, setLocale);
86-
// };
87-
88-
// const currentFlag = computed(() => {
89-
// return `/assets/images/flags/${store.locale?.toUpperCase()}.svg`;
90-
// });
91-
92-
const backgroundImage = computed(() => '/assets/images/auth/bg-gradient.png');
93-
const comingSoonObject1 = computed(() => '/assets/images/auth/coming-soon-object1.png');
94-
const comingSoonObject2 = computed(() => '/assets/images/auth/coming-soon-object2.png');
95-
const comingSoonObject3 = computed(() => '/assets/images/auth/coming-soon-object3.png');
96-
const polygonObject = computed(() => '/assets/images/auth/polygon-object.svg');
97-
const mapBackgroundImage = computed(() => '/assets/images/auth/map.png');
98-
const loginCover = computed(() => '/assets/images/auth/login-cover.png');
99-
100-
// Handle redirect parameter
101-
onMounted(() => {
102-
const redirectUrl = route.query.redirect as string;
103-
if (redirectUrl) {
104-
// Store redirect URL in session storage
105-
sessionStorage.setItem('auth_redirect_url', redirectUrl);
106-
}
107-
108-
authentication.loginAsAnonymous();
109-
});
110-
111-
function triggerGoogleLoginProcess() {
112-
const config = useRuntimeConfig();
113-
const redirectUrl = route.query.redirect as string;
114-
115-
let url = `${config.public.BASE_URL_API}/auth/google`;
116-
117-
// Pass redirect parameter to backend if present
118-
if (redirectUrl) {
119-
const urlParams = new URLSearchParams({ redirect: redirectUrl });
120-
url += `?${urlParams.toString()}`;
121-
}
122-
123-
window.open(url, '_self');
57+
// import { useAppStore } from '@/stores/index';
58+
import { useRouter, useRoute } from 'vue-router';
59+
import { computed, onMounted } from 'vue';
60+
import { Button } from '@codebridger/lib-vue-components/elements.ts';
61+
import { authentication } from '@modular-rest/client';
62+
63+
const { t } = useI18n();
64+
65+
useHead({ title: t('auth.login_page') });
66+
67+
const router = useRouter();
68+
const route = useRoute();
69+
70+
definePageMeta({
71+
layout: 'auth',
72+
});
73+
74+
// const store = useAppStore();
75+
// const { setLocale } = useI18n();
76+
77+
// multi language
78+
// const changeLanguage = (item: any) => {
79+
// appSetting.toggleLanguage(item, setLocale);
80+
// };
81+
82+
// const currentFlag = computed(() => {
83+
// return `/assets/images/flags/${store.locale?.toUpperCase()}.svg`;
84+
// });
85+
86+
const backgroundImage = computed(() => '/assets/images/auth/bg-gradient.png');
87+
const comingSoonObject1 = computed(() => '/assets/images/auth/coming-soon-object1.png');
88+
const comingSoonObject2 = computed(() => '/assets/images/auth/coming-soon-object2.png');
89+
const comingSoonObject3 = computed(() => '/assets/images/auth/coming-soon-object3.png');
90+
const polygonObject = computed(() => '/assets/images/auth/polygon-object.svg');
91+
const mapBackgroundImage = computed(() => '/assets/images/auth/map.png');
92+
const loginCover = computed(() => '/assets/images/auth/login-cover.png');
93+
94+
// Handle redirect parameter
95+
onMounted(() => {
96+
const redirectUrl = route.query.redirect as string;
97+
if (redirectUrl) {
98+
// Store redirect URL in session storage
99+
sessionStorage.setItem('auth_redirect_url', redirectUrl);
124100
}
101+
102+
authentication.loginAsAnonymous();
103+
});
104+
105+
function triggerGoogleLoginProcess() {
106+
const config = useRuntimeConfig();
107+
const redirectUrl = route.query.redirect as string;
108+
109+
let url = `${config.public.BASE_URL_API}/auth/google`;
110+
111+
// Pass redirect parameter to backend if present
112+
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
113+
const params: Record<string, string> = { timezone: timeZone };
114+
115+
if (redirectUrl) {
116+
params.redirect = redirectUrl;
117+
}
118+
119+
const urlParams = new URLSearchParams(params);
120+
url += `?${urlParams.toString()}`;
121+
122+
window.open(url, '_self');
123+
}
125124
</script>

0 commit comments

Comments
 (0)