Skip to content

Commit

Permalink
Add navbar, ticket explore page and ticket view page. Improve login s…
Browse files Browse the repository at this point in the history
…ystem.
  • Loading branch information
ar00n committed Sep 19, 2023
1 parent 8df2dc7 commit f49adb0
Show file tree
Hide file tree
Showing 19 changed files with 2,123 additions and 132 deletions.
998 changes: 928 additions & 70 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,19 @@
},
"dependencies": {
"@hookform/resolvers": "^3.3.1",
"@radix-ui/react-checkbox": "^1.0.4",
"@radix-ui/react-dropdown-menu": "^2.0.5",
"@radix-ui/react-label": "^2.0.2",
"@radix-ui/react-navigation-menu": "^1.1.3",
"@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-slider": "^1.1.2",
"@radix-ui/react-slot": "^1.0.2",
"@tanstack/react-table": "^8.10.0",
"autoprefixer": "10.4.15",
"better-sqlite3": "^8.6.0",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"dayjs": "^1.11.10",
"eslint-config-next": "13.4.19",
"knex": "^2.5.1",
"lucide-react": "^0.279.0",
Expand Down
8 changes: 7 additions & 1 deletion src/app/layout.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Navbar from '@/components/Navbar'
import './globals.css'
import { Inter } from 'next/font/google'

Expand All @@ -11,7 +12,12 @@ export const metadata = {
export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
<body className={inter.className}>
<header>
<Navbar />
</header>
{children}
</body>
</html>
)
}
88 changes: 45 additions & 43 deletions src/app/login/page.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,52 +43,54 @@ export default function LoginForm () {
const res = await login(values.username, values.password)
setResult(res)
if (res.success) {
setTimeout(() => router.push('/'), 2000)
setTimeout(() => window.location.href = '/', 1500)
}
}

return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<FormField
control={form.control}
name="username"
render={({ field }) => (
<FormItem>
<FormLabel>Username</FormLabel>
<FormControl>
<Input placeholder="shadcn" {...field} />
</FormControl>
<FormDescription>
This is your public display name.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<FormLabel>Password</FormLabel>
<FormControl>
<Input placeholder="shadcn" {...field} />
</FormControl>
<FormDescription>
This is your public display name.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
{
result.success != null ?
<Alert variant={result.success ? 'success' : 'destructive'}>{result.message}</Alert>
: ''
}
<Button type="submit">Submit</Button>
</form>
</Form>
<div className='p-6'>
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<FormField
control={form.control}
name="username"
render={({ field }) => (
<FormItem>
<FormLabel>Username</FormLabel>
<FormControl>
<Input placeholder="shadcn" {...field} />
</FormControl>
<FormDescription>
This is your public display name.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="password"
render={({ field }) => (
<FormItem>
<FormLabel>Password</FormLabel>
<FormControl>
<Input placeholder="shadcn" {...field} />
</FormControl>
<FormDescription>
This is your public display name.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
{
result.success != null ?
<Alert variant={result.success ? 'success' : 'destructive'}>{result.message}</Alert>
: ''
}
<Button type="submit">Submit</Button>
</form>
</Form>
</div>
)
}
28 changes: 28 additions & 0 deletions src/app/tickets/[id]/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { getTicket } from "@/lib/tickets"
const dayjs = require('dayjs')
var localizedFormat = require('dayjs/plugin/localizedFormat')
dayjs.extend(localizedFormat)

export default async function TicketView ({ params }) {
if(isNaN(Number(params.id))) {
return <a>Invalid ticket ID.</a>
}

const data = await getTicket(params.id)

if (!data.success) {
return <a>{data.message}</a>
}

return (
<div>
<h1 className="text-2xl">{data.ticket.title}</h1>
<h3 className="text-xs">{dayjs(data.ticket.created_at).format('L LT')}</h3>
<p className="pt-2">{data.ticket.message}</p>

<p>Severity: {data.ticket.severity}</p>
<p>Requester: {data.ticket.requester}</p>
<p>Assignee: {data.ticket .assignee ? data.assignee : 'N/A'}</p>
</div>
)
}
119 changes: 119 additions & 0 deletions src/app/tickets/create/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
"use client"

import React, { useEffect, useState } from 'react'

import { useRouter } from 'next/navigation'

import { useForm } from "react-hook-form"
import * as z from "zod"

import { zodResolver } from "@hookform/resolvers/zod"
import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from "@/components/ui/form"
import { Button } from "@/components/ui/button"
import { Input } from '@/components/ui/input'
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert'
import { verifySession } from '@/lib/user'
import { Slider } from '@/components/ui/slider'
import { Textarea } from '@/components/ui/textarea'
import { createTicket } from '@/lib/tickets'
import { AlertCircle, CheckCircle2 } from 'lucide-react'

const formSchema = z.object({
title: z.string().min(8).max(32),
severity: z.number().min(1).max(5),
message: z.string().min(8).max(32)
})

export default function CreateTicketForm () {
const [result, setResult] = useState({})
const router = useRouter();

useEffect(() => {
verifySession().then(res => {
if (!res.success) {
router.push('/login')
}
})
}, [])

const form = useForm({
resolver: zodResolver(formSchema),
defaultValues: {
title: "",
severity: 5,
message: "",
},
})

async function onSubmit(values) {
const res = await createTicket(values)
setResult(res)
if (res.success) {
setTimeout(() => router.push('/'), 2000)
}
}

return (
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
<FormField
control={form.control}
name="title"
render={({ field }) => (
<FormItem>
<FormLabel>Title</FormLabel>
<FormControl>
<Input placeholder="shadcn" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="severity"
render={({ field: { value, onChange } }) => (
<FormItem>
<FormLabel>Severity: {value}</FormLabel>
<FormControl>
<Slider defaultValue={[5]} max={5} min={1} step={1} inverted={true} x={value} onValueChange={(e) => {onChange(e[0])}} />
</FormControl>
<FormDescription>
This is your public display name.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="message"
render={({ field }) => (
<FormItem>
<FormLabel>Message</FormLabel>
<FormControl>
<Textarea placeholder="shadcn" {...field} />
</FormControl>
<FormDescription>
This is your public display name.
</FormDescription>
<FormMessage />
</FormItem>
)}
/>
{
result.success != null ?
<Alert variant={result.success ? 'success' : 'destructive'}>
{result.success ? <CheckCircle2 className="h-4 w-4" /> : <AlertCircle className="h-4 w-4" />}
<AlertTitle>{result.success ? 'Success' : 'Error'}</AlertTitle>
<AlertDescription>
{result.message}
</AlertDescription>
</Alert>
: ''
}
<Button type="submit">Create</Button>
</form>
</Form>
)
}
13 changes: 11 additions & 2 deletions src/app/tickets/page.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
export default function Tickets() {
import TicketTable from "@/components/TicketTable"
import { getTickets } from "@/lib/tickets"

export default async function Tickets() {
const data = await getTickets(1, 10)

if (!data.success) {
return <a>Error: {data.message}</a>
}

return (

<TicketTable data={data.tickets} />
)
}
Loading

0 comments on commit f49adb0

Please sign in to comment.