UI: Fix ticket dialogs, i18n interpolation, and Add Job button

- Place Category and Priority side by side in create ticket dialogs
- Fix pagination showing literal {1} instead of actual values
- Fix double-brace interpolation in en.json (tickets, companies)
- Replace Add Job modal on dashboard with link to /dashboard/jobs/new
This commit is contained in:
Redbull Deployer 2026-03-04 15:31:41 -06:00
parent 45ffd5033e
commit 1a449b7824
4 changed files with 88 additions and 140 deletions

View file

@ -97,57 +97,59 @@ export default function TicketsPage() {
<DialogTitle>Create New Ticket</DialogTitle>
<DialogDescription>Describe your issue and priority.</DialogDescription>
</DialogHeader>
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="subject" className="text-right">Subject</Label>
<div className="space-y-4 py-4">
<div className="space-y-1.5">
<Label htmlFor="subject">Subject</Label>
<Input
id="subject"
placeholder="Describe your issue briefly"
value={newTicket.subject}
onChange={(e) => setNewTicket({ ...newTicket, subject: e.target.value })}
className="col-span-3"
/>
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="category" className="text-right">Category</Label>
<Select
value={newTicket.category}
onValueChange={(val) => setNewTicket({ ...newTicket, category: val })}
>
<SelectTrigger className="col-span-3">
<SelectValue placeholder="Select category" />
</SelectTrigger>
<SelectContent>
<SelectItem value="bug">Bug</SelectItem>
<SelectItem value="feature">Feature Request</SelectItem>
<SelectItem value="support">Support</SelectItem>
<SelectItem value="billing">Billing</SelectItem>
<SelectItem value="other">Other</SelectItem>
</SelectContent>
</Select>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-1.5">
<Label htmlFor="category">Category</Label>
<Select
value={newTicket.category}
onValueChange={(val) => setNewTicket({ ...newTicket, category: val })}
>
<SelectTrigger>
<SelectValue placeholder="Select category" />
</SelectTrigger>
<SelectContent>
<SelectItem value="bug">Bug</SelectItem>
<SelectItem value="feature">Feature Request</SelectItem>
<SelectItem value="support">Support</SelectItem>
<SelectItem value="billing">Billing</SelectItem>
<SelectItem value="other">Other</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-1.5">
<Label htmlFor="priority">Priority</Label>
<Select
value={newTicket.priority}
onValueChange={(val) => setNewTicket({ ...newTicket, priority: val })}
>
<SelectTrigger>
<SelectValue placeholder="Select priority" />
</SelectTrigger>
<SelectContent>
<SelectItem value="low">Low</SelectItem>
<SelectItem value="medium">Medium</SelectItem>
<SelectItem value="high">High</SelectItem>
</SelectContent>
</Select>
</div>
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="priority" className="text-right">Priority</Label>
<Select
value={newTicket.priority}
onValueChange={(val) => setNewTicket({ ...newTicket, priority: val })}
>
<SelectTrigger className="col-span-3">
<SelectValue placeholder="Select priority" />
</SelectTrigger>
<SelectContent>
<SelectItem value="low">Low</SelectItem>
<SelectItem value="medium">Medium</SelectItem>
<SelectItem value="high">High</SelectItem>
</SelectContent>
</Select>
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="message" className="text-right">Message</Label>
<div className="space-y-1.5">
<Label htmlFor="message">Message</Label>
<Textarea
id="message"
placeholder="Describe your request in detail"
value={newTicket.message}
onChange={(e) => setNewTicket({ ...newTicket, message: e.target.value })}
className="col-span-3"
rows={4}
/>
</div>

View file

@ -312,23 +312,41 @@ export default function AdminTicketsPage() {
placeholder={t("ticketsPage.createDialog.subjectPlaceholder")}
/>
</div>
<div className="space-y-2">
<Label htmlFor="category">{t("ticketsPage.createDialog.category")}</Label>
<Select
value={newTicket.category}
onValueChange={(value) => setNewTicket(prev => ({ ...prev, category: value }))}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="bug">{t("ticketsPage.category.bug")}</SelectItem>
<SelectItem value="feature">{t("ticketsPage.category.feature")}</SelectItem>
<SelectItem value="support">{t("ticketsPage.category.support")}</SelectItem>
<SelectItem value="billing">{t("ticketsPage.category.billing")}</SelectItem>
<SelectItem value="other">{t("ticketsPage.category.other")}</SelectItem>
</SelectContent>
</Select>
<div className="grid grid-cols-2 gap-4">
<div className="space-y-2">
<Label htmlFor="category">{t("ticketsPage.createDialog.category")}</Label>
<Select
value={newTicket.category}
onValueChange={(value) => setNewTicket(prev => ({ ...prev, category: value }))}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="bug">{t("ticketsPage.category.bug")}</SelectItem>
<SelectItem value="feature">{t("ticketsPage.category.feature")}</SelectItem>
<SelectItem value="support">{t("ticketsPage.category.support")}</SelectItem>
<SelectItem value="billing">{t("ticketsPage.category.billing")}</SelectItem>
<SelectItem value="other">{t("ticketsPage.category.other")}</SelectItem>
</SelectContent>
</Select>
</div>
<div className="space-y-2">
<Label htmlFor="priority">{t("ticketsPage.createDialog.priority")}</Label>
<Select
value={newTicket.priority}
onValueChange={(value) => setNewTicket(prev => ({ ...prev, priority: value }))}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="low">{t("ticketsPage.priority.low")}</SelectItem>
<SelectItem value="medium">{t("ticketsPage.priority.medium")}</SelectItem>
<SelectItem value="high">{t("ticketsPage.priority.high")}</SelectItem>
</SelectContent>
</Select>
</div>
</div>
<div className="space-y-2">
<Label htmlFor="message">{t("ticketsPage.createDialog.message")}</Label>
@ -340,22 +358,6 @@ export default function AdminTicketsPage() {
rows={4}
/>
</div>
<div className="space-y-2">
<Label htmlFor="priority">{t("ticketsPage.createDialog.priority")}</Label>
<Select
value={newTicket.priority}
onValueChange={(value) => setNewTicket(prev => ({ ...prev, priority: value }))}
>
<SelectTrigger>
<SelectValue />
</SelectTrigger>
<SelectContent>
<SelectItem value="low">{t("ticketsPage.priority.low")}</SelectItem>
<SelectItem value="medium">{t("ticketsPage.priority.medium")}</SelectItem>
<SelectItem value="high">{t("ticketsPage.priority.high")}</SelectItem>
</SelectContent>
</Select>
</div>
</div>
<DialogFooter>
<Button variant="outline" onClick={() => setCreateOpen(false)}>{t("ticketsPage.createDialog.cancel")}</Button>

View file

@ -1,24 +1,12 @@
"use client"
import { useEffect, useState } from "react"
import Link from "next/link"
import { StatsCard } from "@/components/stats-card"
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"
import { Badge } from "@/components/ui/badge"
import {
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog"
import { Label } from "@/components/ui/label"
import { Textarea } from "@/components/ui/textarea"
import { Input } from "@/components/ui/input"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Briefcase, Users, TrendingUp, FileText, Plus, MoreHorizontal, Loader2 } from "lucide-react"
import { motion } from "framer-motion"
import { adminJobsApi, adminCandidatesApi, type AdminJob, type AdminCandidate, type AdminCandidateStats } from "@/lib/api"
@ -26,7 +14,6 @@ import { toast } from "sonner"
import { useTranslation } from "@/lib/i18n"
export function AdminDashboardContent() {
const [isDialogOpen, setIsDialogOpen] = useState(false)
const [isLoading, setIsLoading] = useState(true)
const { t } = useTranslation()
@ -39,11 +26,6 @@ export function AdminDashboardContent() {
const [recentJobs, setRecentJobs] = useState<AdminJob[]>([])
const [recentCandidates, setRecentCandidates] = useState<AdminCandidate[]>([])
// Fallback company options for the create job dialog (still static or needs Company API,
// keeping static list for now as "Add Job" on dashboard is a quick action, user specified fixing dashboard DATA)
// Actually, I should probably fetch companies too if I want this dialog to work, but let's focus on dashboard VIEW first as requested.
const companyOptions = ["TechCorp", "DesignHub", "DataFlow", "InnovateLab", "AppMakers"]
useEffect(() => {
const loadDashboardData = async () => {
try {
@ -148,50 +130,12 @@ export function AdminDashboardContent() {
<Card>
<CardHeader className="flex flex-row items-center justify-between">
<CardTitle>{t('admin.dashboard.jobs.title')}</CardTitle>
<Dialog open={isDialogOpen} onOpenChange={setIsDialogOpen}>
<DialogTrigger asChild>
<Button>
<Plus className="mr-2 h-4 w-4" />
{t('admin.dashboard.jobs.add')}
</Button>
</DialogTrigger>
<DialogContent className="max-w-2xl">
<DialogHeader>
<DialogTitle>Create new job</DialogTitle>
<DialogDescription>Fill in the details for the new job opening</DialogDescription>
</DialogHeader>
<div className="grid gap-4 py-4">
{/* Simplified form for visual completeness, functional logic should be invalid/mocked for now or wired later */}
<div className="grid gap-2">
<Label htmlFor="dashboard-title">Job title</Label>
<Input id="dashboard-title" placeholder="e.g. Full Stack Developer" />
</div>
<div className="grid gap-2">
<Label htmlFor="dashboard-company">Company</Label>
<Select>
<SelectTrigger id="dashboard-company">
<SelectValue placeholder="Select a company" />
</SelectTrigger>
<SelectContent>
{companyOptions.map((company) => (
<SelectItem key={company} value={company}>
{company}
</SelectItem>
))}
</SelectContent>
</Select>
</div>
{/* ... truncated other fields for brevity/focus on dashboard view ... */}
<p className="text-sm text-muted-foreground">Go to Jobs page for full creation.</p>
</div>
<DialogFooter>
<Button variant="outline" onClick={() => setIsDialogOpen(false)}>
Cancel
</Button>
<Button onClick={() => setIsDialogOpen(false)}>Publish job</Button>
</DialogFooter>
</DialogContent>
</Dialog>
<Link href="/dashboard/jobs/new">
<Button>
<Plus className="mr-2 h-4 w-4" />
{t('admin.dashboard.jobs.add')}
</Button>
</Link>
</CardHeader>
<CardContent>
<Table>

View file

@ -1189,15 +1189,15 @@
"created": "Created",
"actions": "Actions",
"empty": "No companies found",
"showing": "Showing {{from}}-{{to}} of {{total}}"
"showing": "Showing {from}-{to} of {total}"
},
"searchPlaceholder": "Search companies by name or email...",
"deleteConfirm": "Are you sure you want to delete {{name}}? This action cannot be undone.",
"deleteConfirm": "Are you sure you want to delete {name}? This action cannot be undone.",
"success": {
"created": "Company created successfully!",
"deleted": "Company deleted successfully",
"updated": "Company updated successfully",
"statusUpdated": "Company {{field}} updated"
"statusUpdated": "Company {field} updated"
},
"fields": {
"active": "Active",
@ -1309,7 +1309,7 @@
"low": "Low"
},
"pagination": {
"showing": "Showing {{start}} to {{end}} of {{total}} tickets"
"showing": "Showing {start} to {end} of {total} tickets"
},
"deleteDialog": {
"title": "Delete Ticket",