Skip to content

Commit

Permalink
chore(identity): improve redirects after login/logout
Browse files Browse the repository at this point in the history
  • Loading branch information
andypf committed Jan 24, 2025
1 parent 778402b commit 1c16dc2
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 9 deletions.
12 changes: 8 additions & 4 deletions apps/aurora-portal/src/client/Shell/AuthProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@ interface LoginParams {
}

interface User {
id: string
name: string
domain: string
password_expires_at: string
session_expires_at: string
}

interface AuthApi {
login: (props: LoginParams) => void
logout: () => void
login: (props: LoginParams) => Promise<void>
logout: () => Promise<void>
error: string | null
isLoading: boolean
user: User | null
Expand All @@ -39,7 +43,7 @@ const useAuthApi = (): AuthApi => {

const login = (props: LoginParams) => {
setAuth({ ...auth, error: null, isLoading: true })
trpcClient.identity.login
return trpcClient.identity.login
.mutate(props)
.then((res) => {
setAuth({ user: res.user, error: null, isLoading: false })
Expand All @@ -49,7 +53,7 @@ const useAuthApi = (): AuthApi => {

const logout = () => {
setAuth({ ...auth, error: null, isLoading: true })
trpcClient.identity.logout
return trpcClient.identity.logout
.mutate()
.then(() => {
setAuth({ user: null, error: null, isLoading: false })
Expand Down
47 changes: 46 additions & 1 deletion apps/aurora-portal/src/client/Shell/Navigation/UserMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,60 @@
import { useState, useEffect } from "react"
import { useLocation } from "wouter"
import { Button, Icon } from "@cloudoperators/juno-ui-components"
import { useAuth } from "../../Shell/AuthProvider"

function Countdown(props: { className?: string; passwordExpiresAt: string }) {
const [timeLeft, setTimeLeft] = useState<string>("")

useEffect(() => {
const expirationDate = new Date(props.passwordExpiresAt)

const updateCountdown = () => {
const now = new Date()
const timeDiff = expirationDate.getTime() - now.getTime()

if (timeDiff <= 0) {
setTimeLeft("expired!")
return
}

const days = Math.floor(timeDiff / (1000 * 60 * 60 * 24))
const hours = Math.floor((timeDiff / (1000 * 60 * 60)) % 24)
const minutes = Math.floor((timeDiff / (1000 * 60)) % 60)
const seconds = Math.floor((timeDiff / 1000) % 60)
let timeLeft = ""
if (days > 0) timeLeft += `${days}d `
if (hours > 0) timeLeft += `${hours}h `
if (minutes > 0) timeLeft += `${minutes}m `
setTimeLeft(`${timeLeft} ${seconds}s`)
}

// Initial update
updateCountdown()

// Update every second
const intervalId = setInterval(updateCountdown, 1000)

// Cleanup interval on component unmount
return () => clearInterval(intervalId)
}, [props.passwordExpiresAt])

return <div className="text-xs pt-2 pb-2 text-theme-light">{timeLeft}</div>
}

export function UserMenu() {
const { user, isLoading, logout } = useAuth()
const { user, isLoading, logout: authLogout } = useAuth()

const setLocation = useLocation()[1]

const login = () => {
setLocation("/auth/signin")
}

const logout = () => {
authLogout().then(() => setLocation("/"))
}

return (
<div className="mt-5 pt-5 w-24 flex justify-center items-center">
{user ? (
Expand All @@ -20,6 +64,7 @@ export function UserMenu() {
<Button disabled={isLoading} variant="default" size="small" onClick={logout}>
Sign Out
</Button>
<Countdown passwordExpiresAt={user.session_expires_at} />
</div>
) : (
<Button disabled={isLoading} variant="primary" size="small" onClick={login} className="mr-2 ml-2">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,11 @@ export const tokenRouter = {
return { isAuthenticated: false, user: null, reason: token.statusText }
}
const tokenData = await token.json().then((data) => data.token)

return { isAuthenticated: true, user: tokenData.user, reason: null }
return {
isAuthenticated: true,
user: { ...tokenData.user, session_expires_at: tokenData.expires_at },
reason: null,
}
}),
login: publicProcedure
.input(z.object({ user: z.string(), password: z.string(), domainName: z.string() }))
Expand All @@ -31,7 +34,7 @@ export const tokenRouter = {
const expDate = new Date(tokenData.expires_at)

ctx.setSessionCookie(authToken, { expires: expDate })
return { user: tokenData.user }
return { user: { ...tokenData.user, session_expires_at: tokenData.expires_at } }
}),

logout: publicProcedure.mutation(async ({ ctx }) => {
Expand Down
2 changes: 1 addition & 1 deletion apps/aurora-portal/src/polaris-bff/trpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const mergeRouters = t.mergeRouters
export const publicProcedure = t.procedure

export const protectedProcedure = publicProcedure.use(function isAuthed(opts) {
if (opts.ctx.getSessionCookie() === null) {
if (opts.ctx.getSessionCookie() === null || opts.ctx.getSessionCookie() === undefined) {
throw new TRPCError({
code: "UNAUTHORIZED",
})
Expand Down

0 comments on commit 1c16dc2

Please sign in to comment.