Skip to content

Commit

Permalink
feat(dashboard): responsive card for api key (#3506)
Browse files Browse the repository at this point in the history
Co-authored-by: Siddharth <[email protected]>
  • Loading branch information
siddhart1o1 and Siddharth authored Nov 8, 2023
1 parent c6091ad commit e7d4d16
Show file tree
Hide file tree
Showing 5 changed files with 244 additions and 88 deletions.
51 changes: 50 additions & 1 deletion apps/dashboard/app/api-keys/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,32 @@
import { Box, Link, Typography } from "@mui/joy"

import { redirect } from "next/navigation"

import { getServerSession } from "next-auth"

import { authOptions } from "../api/auth/[...nextauth]/route"

import ContentContainer from "@/components/content-container"
import ApiKeysList from "@/components/api-keys/list"
import ApiKeyCreate from "@/components/api-keys/create"
import ApiKeysCard from "@/components/api-keys/api-card"

import { apiKeys } from "@/services/graphql/queries/api-keys"

export default async function Home() {
const session = await getServerSession(authOptions)
const token = session?.accessToken

if (!token || typeof token !== "string") {
redirect("/")
}

const keys = await apiKeys(token)

const activeKeys = keys.filter(({ expired, revoked }) => !expired && !revoked)
const expiredKeys = keys.filter(({ expired }) => expired)
const revokedKeys = keys.filter(({ revoked }) => revoked)

return (
<ContentContainer>
<Box
Expand Down Expand Up @@ -35,7 +57,34 @@ export default async function Home() {
</Typography>
<ApiKeyCreate />
</Box>
<ApiKeysList />
<Box
sx={{
display: { xs: "none", md: "flex" },
flexDirection: "column",
rowGap: "1em",
width: "100%",
}}
>
<ApiKeysList
activeKeys={activeKeys}
expiredKeys={expiredKeys}
revokedKeys={revokedKeys}
/>
</Box>
<Box
sx={{
display: { xs: "flex", md: "none" },
flexDirection: "column",
rowGap: "1em",
width: "100%",
}}
>
<ApiKeysCard
activeKeys={activeKeys}
expiredKeys={expiredKeys}
revokedKeys={revokedKeys}
/>
</Box>
</Box>
</ContentContainer>
)
Expand Down
75 changes: 75 additions & 0 deletions apps/dashboard/components/api-keys/api-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React from "react"

import { Card, Divider, Typography, Box } from "@mui/joy"

import RevokeKey from "./revoke"

interface ApiKey {
id: string
name: string
createdAt: string
expiresAt: string
lastUsedAt?: string | null
expired: boolean
revoked: boolean
}

const formatDate = (timestamp: string): string => {
const options: Intl.DateTimeFormatOptions = {
year: "numeric",
month: "long",
day: "2-digit",
}
return new Date(parseInt(timestamp) * 1000).toLocaleDateString(undefined, options)
}

interface ApiKeysCardProps {
activeKeys: ApiKey[]
expiredKeys: ApiKey[]
revokedKeys: ApiKey[]
}

const ApiKeysCard: React.FC<ApiKeysCardProps> = ({
activeKeys,
expiredKeys,
revokedKeys,
}: ApiKeysCardProps) => {
const renderKeyCards = (keyArray: ApiKey[], title: string) => (
<>
<Typography fontSize={22}>{title}</Typography>
{keyArray.length === 0 ? (
<Typography>No keys to display.</Typography>
) : (
keyArray.map((key: ApiKey) => (
<Card key={key.id} sx={{ width: "100%", mb: 2 }}>
<Typography fontSize={14}>{key.id}</Typography>
<Typography fontSize={18} fontWeight={"bolder"}>
{key.name}
</Typography>
<Divider />
<Box sx={{ display: "flex", justifyContent: "space-between" }}>
<Typography fontSize={13}>Created At</Typography>
<Typography fontSize={13}>{formatDate(key.createdAt)}</Typography>
</Box>
<Box sx={{ display: "flex", justifyContent: "space-between" }}>
<Typography fontSize={13}>Expires At</Typography>
<Typography fontSize={13}>{formatDate(key.expiresAt)}</Typography>
</Box>
{!key.revoked && !key.expired && <RevokeKey id={key.id} />}
</Card>
))
)}
<Divider />
</>
)

return (
<>
{renderKeyCards(activeKeys, "Active Keys")}
{renderKeyCards(revokedKeys, "Revoked Keys")}
{renderKeyCards(expiredKeys, "Expired Keys")}
</>
)
}

export default ApiKeysCard
77 changes: 48 additions & 29 deletions apps/dashboard/components/api-keys/create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ const ApiKeyCreate = () => {
<Typography
sx={{
p: "1em",
width: "100%",
borderRadius: "0.5em",
}}
variant="outlined"
color="success"
Expand Down Expand Up @@ -170,39 +172,55 @@ const ApiKeyCreate = () => {
}}
action={formAction}
>
<Typography>Name</Typography>
<Input
name="apiKeyName"
id="apiKeyName"
<Box
sx={{
padding: "0.6em",
width: "100%",
display: "flex",
flexDirection: "column",
gap: "0.2em",
}}
placeholder="API Key Name *"
/>

<Typography>Expires In</Typography>

<Input
name="apiKeyExpiresInDays"
id="apiKeyExpiresInDays"
sx={{ display: "none" }}
/>

<Select
placeholder="Expires In"
onChange={(_, v) => {
if (v === "custom") {
setEnableCustomExpiresInDays(true)
setExpiresInDays(30)
}
if (v && v !== "custom") setExpiresInDays(parseInt(String(v)))
>
<Typography>Name</Typography>
<Input
name="apiKeyName"
id="apiKeyName"
sx={{
padding: "0.6em",
width: "100%",
}}
placeholder="API Key Name *"
/>
</Box>
<Box
sx={{
display: "flex",
flexDirection: "column",
gap: "0.2em",
}}
>
<Option value="30">30 days</Option>
<Option value="90">90 days</Option>
<Option value="custom">Custom</Option>
</Select>
<Typography>Expires In</Typography>
<Input
name="apiKeyExpiresInDays"
id="apiKeyExpiresInDays"
sx={{ display: "none", padding: "0.6em" }}
/>
<Select
sx={{
padding: "0.6em",
}}
placeholder="Expires In"
onChange={(_, v) => {
if (v === "custom") {
setEnableCustomExpiresInDays(true)
setExpiresInDays(30)
}
if (v && v !== "custom") setExpiresInDays(parseInt(String(v)))
}}
>
<Option value="30">30 days</Option>
<Option value="90">90 days</Option>
<Option value="custom">Custom</Option>
</Select>
</Box>

{enableCustomExpiresInDays && (
<Box
Expand All @@ -216,6 +234,7 @@ const ApiKeyCreate = () => {
<Input
sx={{
width: "100%",
padding: "0.6em",
}}
onChange={(e) => {
if (e.target.value && parseInt(e.target.value) > 0)
Expand Down
Loading

0 comments on commit e7d4d16

Please sign in to comment.