chore: code review

This commit is contained in:
Jin Yi
2025-09-12 19:41:01 +09:00
parent 4b2409f6c4
commit f37d50545d
13 changed files with 133 additions and 151 deletions

76
src/api/auth.ts Normal file
View File

@@ -0,0 +1,76 @@
// Mock API for authentication and user onboarding
// TODO: Replace with actual API calls when backend is ready
// ============ Types ============
export interface UserOnboardingStatus {
surveyCompleted: boolean
whitelisted: boolean
email?: string
}
export interface SimpleUser {
emailVerified: boolean
surveyCompleted: boolean
whitelisted: boolean
}
// ============ User Status ============
export async function getMe(): Promise<UserOnboardingStatus | null> {
// Simulate API delay
await new Promise((resolve) => setTimeout(resolve, 300))
// Check localStorage for mock onboarding status
const surveyCompleted = localStorage.getItem('surveyCompleted')
const whitelisted = localStorage.getItem('whitelisted')
const userEmail = localStorage.getItem('userEmail')
// Return user status
return {
surveyCompleted: surveyCompleted === 'true',
whitelisted: whitelisted === 'true',
email: userEmail || undefined
}
}
export function getAuthStatus(): SimpleUser {
const emailVerified = localStorage.getItem('emailVerified')
const surveyCompleted = localStorage.getItem('surveyCompleted')
const whitelisted = localStorage.getItem('whitelisted')
return {
emailVerified: emailVerified === 'true',
surveyCompleted: surveyCompleted === 'true',
whitelisted: whitelisted === 'true'
}
}
// ============ Auth Actions ============
export function verifyEmail(): void {
localStorage.setItem('emailVerified', 'true')
}
export function completeSurvey(): void {
localStorage.setItem('surveyCompleted', 'true')
}
export function claimInvite(code: string): boolean {
const validCodes = ['test']
if (validCodes.includes(code)) {
localStorage.setItem('whitelisted', 'true')
return true
}
return false
}
// ============ Mock Data Helpers ============
export function setMockUserData(data: Partial<UserOnboardingStatus>) {
if (data.surveyCompleted !== undefined) {
localStorage.setItem(
'surveyCompleted',
data.surveyCompleted ? 'true' : 'false'
)
}
if (data.whitelisted !== undefined) {
localStorage.setItem('whitelisted', data.whitelisted ? 'true' : 'false')
}
}

View File

@@ -1,39 +0,0 @@
// Mock API for user onboarding status
// TODO: Replace with actual API calls when backend is ready
export interface UserOnboardingStatus {
surveyTaken: boolean
whitelisted: boolean
email?: string
userId?: string
}
export async function getMe(): Promise<UserOnboardingStatus | null> {
// Simulate API delay
await new Promise((resolve) => setTimeout(resolve, 300))
// Check localStorage for mock onboarding status
// These values are null if not set (user hasn't completed the step)
const surveyCompleted = localStorage.getItem('surveyCompleted')
const whitelisted = localStorage.getItem('whitelisted')
const userEmail = localStorage.getItem('userEmail')
// Return user status
// If key doesn't exist (null), treat as false
return {
surveyTaken: surveyCompleted === 'true',
whitelisted: whitelisted === 'true',
email: userEmail || undefined,
userId: userEmail || undefined
}
}
// Helper function to update mock data (for testing)
export function setMockUserData(data: Partial<UserOnboardingStatus>) {
if (data.surveyTaken !== undefined) {
localStorage.setItem('surveyCompleted', data.surveyTaken ? 'true' : 'false')
}
if (data.whitelisted !== undefined) {
localStorage.setItem('whitelisted', data.whitelisted ? 'true' : 'false')
}
}

View File

@@ -1,36 +0,0 @@
// Simple mock auth using localStorage
export interface SimpleUser {
emailVerified: boolean
surveyCompleted: boolean
whitelisted: boolean
}
export function getAuthStatus(): SimpleUser {
const emailVerified = localStorage.getItem('emailVerified')
const surveyCompleted = localStorage.getItem('surveyCompleted')
const whitelisted = localStorage.getItem('whitelisted')
return {
emailVerified: emailVerified === null ? false : emailVerified === 'true',
surveyCompleted:
surveyCompleted === null ? false : surveyCompleted === 'true',
whitelisted: whitelisted === null ? false : whitelisted === 'true'
}
}
export function verifyEmail(): void {
localStorage.setItem('emailVerified', 'true')
}
export function completeSurvey(): void {
localStorage.setItem('surveyCompleted', 'true')
}
export function claimInvite(code: string): boolean {
const validCodes = ['test']
if (validCodes.includes(code)) {
localStorage.setItem('whitelisted', 'true')
return true
}
return false
}

View File

@@ -1,6 +1,6 @@
// Mock API for survey submission
// TODO: Replace with actual API calls when backend is ready
import { completeSurvey } from './simpleAuth'
import { completeSurvey } from './auth'
export interface SurveyPayload {
useCase?: string

View File

@@ -1,17 +0,0 @@
// Whitelist management functions
export function isWhitelisted(): boolean {
return localStorage.getItem('whitelisted') === 'true'
}
export function setWhitelisted(value: boolean): void {
localStorage.setItem('whitelisted', value ? 'true' : 'false')
}
export function addToWhitelist(): void {
setWhitelisted(true)
}
export function removeFromWhitelist(): void {
setWhitelisted(false)
}

View File

@@ -1,8 +1,15 @@
<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
<template>
<div class="cloud-claim-invite">
<h1>Processing Invite Code...</h1>
<button @click="onClaim">Claim Invite</button>
<div
class="flex flex-col justify-center items-center h-screen font-mono text-black gap-4"
>
<h1 class="text-2xl">Processing Invite Code...</h1>
<button
class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600 cursor-pointer"
@click="onClaim"
>
Claim Invite
</button>
</div>
</template>
@@ -10,7 +17,7 @@
import { onMounted } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { claimInvite } from '@/api/simpleAuth'
import { claimInvite } from '@/api/auth'
const route = useRoute()
const router = useRouter()
@@ -63,14 +70,3 @@ onMounted(async () => {
}
})
</script>
<style scoped>
.cloud-claim-invite {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
font-family: monospace;
color: #000;
}
</style>

View File

@@ -1,3 +1,4 @@
<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
<template>
<BaseViewTemplate dark>
<div class="flex items-center justify-center min-h-screen p-8">
@@ -65,8 +66,13 @@
<!-- Help text -->
<p class="text-xs text-muted mt-8 text-center">
{{ t('cloudOnboarding.forgotPassword.didntReceiveEmail') }}
<a href="mailto:hello@comfy.org" class="text-blue-500 cursor-pointer">
hello@comfy.org
<a
href="https://support.comfy.org"
class="text-blue-500 cursor-pointer"
target="_blank"
rel="noopener noreferrer"
>
support.comfy.org
</a>
</p>
</div>

View File

@@ -1,6 +1,8 @@
<template>
<div class="cloud-invite-entry">
<h1>{{ inviteCode }}</h1>
<div
class="flex flex-col justify-center items-center h-screen font-mono gap-4"
>
<h1 class="text-2xl">{{ inviteCode }}</h1>
</div>
</template>
@@ -11,27 +13,9 @@ import { useRoute, useRouter } from 'vue-router'
const route = useRoute()
const router = useRouter()
const inviteCode = computed(
() => (route.params.inviteCode as string) || 'No code provided'
(): string => (route.params.inviteCode as string) || 'No code provided'
)
onMounted(() => {
void router.push({ path: '/login', query: { inviteCode: inviteCode.value } })
})
</script>
<style scoped>
.cloud-invite-entry {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
font-family: monospace;
gap: 1rem;
}
button {
padding: 0.5rem 1rem;
margin: 0.25rem;
cursor: pointer;
}
</style>

View File

@@ -1,3 +1,4 @@
<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
<template>
<BaseViewTemplate dark>
<div class="flex items-center justify-center min-h-screen p-8">
@@ -73,9 +74,14 @@
{{ t('auth.login.privacyLink') }} </a
>.
{{ t('auth.login.questionsContactPrefix') }}
<a href="mailto:hello@comfy.org" class="text-blue-500 cursor-pointer">
hello@comfy.org</a
>.
<a
href="https://support.comfy.org"
class="text-blue-500 cursor-pointer"
target="_blank"
rel="noopener noreferrer"
>
support.comfy.org
</a>
</p>
</div>
</div>
@@ -90,7 +96,7 @@ import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRoute, useRouter } from 'vue-router'
import { getMe } from '@/api/me'
import { getMe } from '@/api/auth'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import CloudSignInForm from '@/platform/onboarding/cloud/components/CloudSignInForm.vue'
import { type SignInData } from '@/schemas/signInSchema'
@@ -129,7 +135,7 @@ const onSuccess = async () => {
const me = await getMe()
const redirectPath = route.query.redirect as string
if (me && !me.surveyTaken) {
if (me && !me.surveyCompleted) {
await router.push({ name: 'cloud-survey' })
} else if (me && !me.whitelisted) {
await router.push({ name: 'cloud-waitlist' })

View File

@@ -1,3 +1,4 @@
<!-- eslint-disable @intlify/vue-i18n/no-raw-text -->
<template>
<BaseViewTemplate dark>
<div class="flex items-center justify-center min-h-screen p-8">
@@ -78,9 +79,14 @@
{{ t('auth.login.privacyLink') }} </a
>.
{{ t('auth.login.questionsContactPrefix') }}
<a href="mailto:hello@comfy.org" class="text-blue-500 cursor-pointer">
hello@comfy.org</a
>.
<a
href="https://support.comfy.org"
class="text-blue-500 cursor-pointer"
target="_blank"
rel="noopener noreferrer"
>
support.comfy.org
</a>
</p>
</div>
</div>
@@ -95,7 +101,7 @@ import { onMounted, ref } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRoute, useRouter } from 'vue-router'
import { getMe } from '@/api/me'
import { getMe } from '@/api/auth'
import SignUpForm from '@/components/dialog/content/signin/SignUpForm.vue'
import { useFirebaseAuthActions } from '@/composables/auth/useFirebaseAuthActions'
import { SignUpData } from '@/schemas/signInSchema'
@@ -121,7 +127,7 @@ const onSuccess = async () => {
const me = await getMe()
// Navigate based on user status
if (me && !me.surveyTaken) {
if (me && !me.surveyCompleted) {
void router.push({ name: 'cloud-survey' })
} else if (me && !me.whitelisted) {
void router.push({ name: 'cloud-waitlist' })

View File

@@ -9,7 +9,7 @@
import { onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { verifyEmail } from '@/api/simpleAuth'
import { verifyEmail } from '@/api/auth'
const route = useRoute()

View File

@@ -6,7 +6,7 @@ import {
createWebHistory
} from 'vue-router'
import { getMe } from '@/api/me'
import { getMe } from '@/api/auth'
import { useDialogService } from '@/services/dialogService'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
import { useUserStore } from '@/stores/userStore'
@@ -81,13 +81,13 @@ const router = createRouter({
// Check onboarding status first
const me = await getMe()
if (me) {
const emailVerified =
localStorage.getItem('emailVerified') === 'true'
// const emailVerified =
// localStorage.getItem('emailVerified') === 'true'
if (!emailVerified) {
return next('/verify-email')
}
if (!me.surveyTaken) {
// if (!emailVerified) {
// return next('/verify-email')
// }
if (!me.surveyCompleted) {
return next('/survey')
}
if (!me.whitelisted) {
@@ -218,7 +218,7 @@ router.beforeEach(async (to, _from, next) => {
) {
try {
const me = await getMe()
if (me && !me.surveyTaken) {
if (me && !me.surveyCompleted) {
return next({ name: 'cloud-survey' })
}
if (me && !me.whitelisted) {

View File

@@ -1,6 +1,6 @@
import type { NavigationGuardNext, RouteLocationNormalized } from 'vue-router'
import { getAuthStatus } from '@/api/simpleAuth'
import { getAuthStatus } from '@/api/auth'
import { useFirebaseAuthStore } from '@/stores/firebaseAuthStore'
export async function cloudOnboardingGuard(