add remember me checkbox

This commit is contained in:
john 2025-05-29 13:21:37 +02:00
parent 334435cf78
commit 3b4f384582
6 changed files with 43 additions and 9 deletions

View file

@ -188,8 +188,7 @@ export interface paths {
requestBody: { requestBody: {
content: { content: {
'multipart/form-data': { 'multipart/form-data': {
/** Format: binary */ file?: components['schemas']['IFormFile']
file?: string
} }
} }
} }
@ -502,6 +501,8 @@ export interface components {
DeletePostReactionRequest: { DeletePostReactionRequest: {
emoji: string emoji: string
} }
/** Format: binary */
IFormFile: string
ListSignupCodesResult: { ListSignupCodesResult: {
signupCodes: components['schemas']['SignupCodeDto'][] signupCodes: components['schemas']['SignupCodeDto'][]
} }
@ -513,6 +514,7 @@ export interface components {
LoginRequest: { LoginRequest: {
username: string username: string
password: string password: string
rememberMe: boolean | null
} }
LoginResponse: { LoginResponse: {
/** Format: uuid */ /** Format: uuid */
@ -560,7 +562,7 @@ export interface components {
username: string username: string
password: string password: string
signupCode: string signupCode: string
email: string | null rememberMe: boolean | null
} }
RegisterResponse: { RegisterResponse: {
/** Format: uuid */ /** Format: uuid */

View file

@ -6,9 +6,9 @@ import { ApiClient } from '../api/client.ts'
export class AuthService { export class AuthService {
constructor(private readonly client: ApiClient) {} constructor(private readonly client: ApiClient) {}
async login(username: string, password: string) { async login(username: string, password: string, rememberMe: boolean = false) {
const res = await this.client.POST('/auth/login', { const res = await this.client.POST('/auth/login', {
body: { username, password }, body: { username, password, rememberMe },
credentials: 'include', credentials: 'include',
}) })
@ -19,9 +19,9 @@ export class AuthService {
dispatchMessage('auth:logged-in', null) dispatchMessage('auth:logged-in', null)
} }
async signup(username: string, password: string, signupCode: string) { async signup(username: string, password: string, signupCode: string, rememberMe: boolean = false) {
const res = await this.client.POST('/auth/register', { const res = await this.client.POST('/auth/register', {
body: { username, password, signupCode, email: null }, body: { username, password, signupCode, email: null, rememberMe },
credentials: 'include', credentials: 'include',
}) })

View file

@ -17,6 +17,7 @@ export default function LoginPage({ authService }: LoginPageProps) {
const [isSubmitting, setIsSubmitting] = useState(false) const [isSubmitting, setIsSubmitting] = useState(false)
const [username, setUsername] = useState('') const [username, setUsername] = useState('')
const [password, setPassword] = useState('') const [password, setPassword] = useState('')
const [rememberMe, setRememberMe] = useState(false)
const [error, setError] = useState<string | null>(null) const [error, setError] = useState<string | null>(null)
const usernameInputRef = useRef<HTMLInputElement | null>(null) const usernameInputRef = useRef<HTMLInputElement | null>(null)
const passwordInputRef = useRef<HTMLInputElement | null>(null) const passwordInputRef = useRef<HTMLInputElement | null>(null)
@ -49,7 +50,7 @@ export default function LoginPage({ authService }: LoginPageProps) {
setIsSubmitting(true) setIsSubmitting(true)
try { try {
await authService.login(username, password) await authService.login(username, password, rememberMe)
} catch (error: unknown) { } catch (error: unknown) {
setError(error instanceof Error ? error.message : 'something went terribly wrong') setError(error instanceof Error ? error.message : 'something went terribly wrong')
} finally { } finally {
@ -95,6 +96,19 @@ export default function LoginPage({ authService }: LoginPageProps) {
/> />
</div> </div>
<div className="flex items-center gap-2 mt-2">
<input
type="checkbox"
id="rememberMe"
checked={rememberMe}
onChange={(e) => setRememberMe(e.target.checked)}
className="h-4 w-4"
/>
<label htmlFor="rememberMe" className="text-sm text-gray-600">
DONT log me out &gt;:(
</label>
</div>
<Button className="mt-4" disabled={isSubmitting} type="submit"> <Button className="mt-4" disabled={isSubmitting} type="submit">
{isSubmitting ? 'wait...' : 'make login pls'} {isSubmitting ? 'wait...' : 'make login pls'}
</Button> </Button>

View file

@ -20,6 +20,7 @@ export default function SignupPage({ authService }: SignupPageProps) {
const { code } = useParams() const { code } = useParams()
const [signupCode, setSignupCode] = useState<string | null>(null) const [signupCode, setSignupCode] = useState<string | null>(null)
const [isSubmitting, setIsSubmitting] = useState(false) const [isSubmitting, setIsSubmitting] = useState(false)
const [rememberMe, setRememberMe] = useState(false)
const [error, setError] = useState<string>('') const [error, setError] = useState<string>('')
const [username, setUsername, usernameError, validateUsername] = const [username, setUsername, usernameError, validateUsername] =
useValidatedInput(isValidUsername) useValidatedInput(isValidUsername)
@ -79,7 +80,7 @@ export default function SignupPage({ authService }: SignupPageProps) {
setIsSubmitting(true) setIsSubmitting(true)
try { try {
await authService.signup(username, password, signupCode) await authService.signup(username, password, signupCode, rememberMe)
navigate('/') navigate('/')
} catch (e: unknown) { } catch (e: unknown) {
const err = e as Error const err = e as Error
@ -116,6 +117,18 @@ export default function SignupPage({ authService }: SignupPageProps) {
type="password" type="password"
ref={passwordInputRef} ref={passwordInputRef}
/> />
<div className="flex items-center gap-2 mt-2">
<input
type="checkbox"
id="rememberMe"
checked={rememberMe}
onChange={(e) => setRememberMe(e.target.checked)}
className="h-4 w-4"
/>
<label htmlFor="rememberMe" className="text-sm text-gray-600">
DONT log me out &gt;:(
</label>
</div>
<Button <Button
className="mt-4" className="mt-4"
disabled={isSubmitting || !!usernameError || !!passwordError} disabled={isSubmitting || !!usernameError || !!passwordError}

View file

@ -15,5 +15,8 @@ export function initApp() {
const mediaService = new MediaService(client) const mediaService = new MediaService(client)
const authService = new AuthService(client) const authService = new AuthService(client)
setGlobal('postsService', postService)
setGlobal('authService', authService)
return { postService, mediaService, authService } return { postService, mediaService, authService }
} }

2
src/types.d.ts vendored
View file

@ -19,4 +19,6 @@ declare global {
export interface FemtoApp { export interface FemtoApp {
version: string version: string
user: User | null user: User | null
authService: AuthService | null
postsService: PostsService | null
} }