Skip to content

Commit

Permalink
feat: authentication, additional pages
Browse files Browse the repository at this point in the history
  • Loading branch information
binglekruger committed Jan 16, 2025
1 parent e4284d3 commit f3652f8
Show file tree
Hide file tree
Showing 27 changed files with 3,223 additions and 215 deletions.
304 changes: 297 additions & 7 deletions ntc-web/app/analysis/page.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,300 @@
'use client'

import { useState } from 'react'
import { Card } from "@/components/ui/card"
import { Input } from "@/components/ui/input"
import { Button } from "@/components/ui/button"
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table"
import { ChevronDown, ChevronUp, ChevronsUpDown } from "lucide-react"

interface AnalysisItem {
name: string
description: string
state: string
listedOnMarketplace: string
}

export default function Analysis() {
return (
<div className="space-y-6">
<h1 className="text-4xl font-bold text-gray-900">Analysis</h1>
<div className="rounded-lg bg-white p-6 shadow-lg">
{/* Add analysis content here */}
</div>
</div>
const [search, setSearch] = useState('')
const [stateFilters, setStateFilters] = useState<string[]>([])
const [marketplaceFilter, setMarketplaceFilter] = useState<string[]>([])
const [sortConfig, setSortConfig] = useState<{
key: keyof AnalysisItem | null;
direction: 'asc' | 'desc' | null;
}>({ key: null, direction: null })

// Sample data
const items: AnalysisItem[] = [
{
name: "Market Analysis 2024",
description: "Consumer behavior trends Q1",
state: "active",
listedOnMarketplace: "yes"
},
{
name: "Financial Metrics",
description: "Revenue analysis by region",
state: "completed",
listedOnMarketplace: "no"
},
{
name: "Customer Demographics",
description: "Age distribution study",
state: "active",
listedOnMarketplace: "yes"
},
{
name: "Sales Performance",
description: "Monthly sales metrics",
state: "pending",
listedOnMarketplace: "no"
},
{
name: "Product Analytics",
description: "Usage patterns Q4 2023",
state: "active",
listedOnMarketplace: "yes"
}
]

// Handle sort
const handleSort = (key: keyof AnalysisItem) => {
let direction: 'asc' | 'desc' | null = 'asc'

if (sortConfig.key === key) {
if (sortConfig.direction === 'asc') direction = 'desc'
else if (sortConfig.direction === 'desc') direction = null
}

setSortConfig({ key, direction })
}

// Get sort icon
const getSortIcon = (key: keyof AnalysisItem) => {
if (sortConfig.key !== key) return <ChevronsUpDown className="h-4 w-4" />
if (sortConfig.direction === 'asc') return <ChevronUp className="h-4 w-4" />
if (sortConfig.direction === 'desc') return <ChevronDown className="h-4 w-4" />
return <ChevronsUpDown className="h-4 w-4" />
}

// Filter and sort items
const filteredAndSortedItems = items
.filter(item => {
const searchTerm = search.toLowerCase()
const matchesSearch =
item.name.toLowerCase().includes(searchTerm) ||
item.description.toLowerCase().includes(searchTerm) ||
item.state.toLowerCase().includes(searchTerm) ||
item.listedOnMarketplace.toLowerCase().includes(searchTerm)

const matchesState = stateFilters.length === 0 || stateFilters.includes(item.state)
const matchesMarketplace = marketplaceFilter.length === 0 || marketplaceFilter.includes(item.listedOnMarketplace)

return matchesSearch && matchesState && matchesMarketplace
})
.sort((a, b) => {
if (!sortConfig.key || !sortConfig.direction) return 0

const aValue = a[sortConfig.key]
const bValue = b[sortConfig.key]

if (aValue < bValue) return sortConfig.direction === 'asc' ? -1 : 1
if (aValue > bValue) return sortConfig.direction === 'asc' ? 1 : -1
return 0
})

// Toggle filter functions
const toggleStateFilter = (state: string) => {
setStateFilters(prev =>
prev.includes(state)
? prev.filter(s => s !== state)
: [...prev, state]
)
}

const toggleMarketplaceFilter = (value: string) => {
setMarketplaceFilter(prev =>
prev.includes(value)
? prev.filter(v => v !== value)
: [...prev, value]
)
}

return (
<div className="space-y-6">
<h1 className="text-4xl font-bold text-gray-900">Analysis</h1>

<Card>
{/* Search and Filters */}
<div className="bg-gray-800 p-4">
<div className="flex items-center gap-4">
<Input
type="text"
placeholder="Search analysis..."
value={search}
onChange={(e) => setSearch(e.target.value)}
className="max-w-xs bg-white"
/>

<div className="flex-1 flex justify-center">
<div className="flex gap-2 mr-16">
<Button
variant="outline"
size="sm"
onClick={() => toggleStateFilter('active')}
className={`bg-white hover:bg-gray-100 min-w-[100px] ${
stateFilters.includes('active') ? 'bg-green-600 text-white hover:bg-green-700' : ''
}`}
>
Active
</Button>
<Button
variant="outline"
size="sm"
onClick={() => toggleStateFilter('pending')}
className={`bg-white hover:bg-gray-100 min-w-[100px] ${
stateFilters.includes('pending') ? 'bg-green-600 text-white hover:bg-green-700' : ''
}`}
>
Pending
</Button>
<Button
variant="outline"
size="sm"
onClick={() => toggleStateFilter('completed')}
className={`bg-white hover:bg-gray-100 min-w-[100px] ${
stateFilters.includes('completed') ? 'bg-green-600 text-white hover:bg-green-700' : ''
}`}
>
Completed
</Button>
</div>

<div className="flex gap-2">
<Button
variant="outline"
size="sm"
onClick={() => toggleMarketplaceFilter('yes')}
className={`bg-white hover:bg-gray-100 min-w-[100px] ${
marketplaceFilter.includes('yes') ? 'bg-green-600 text-white hover:bg-green-700' : ''
}`}
>
Listed
</Button>
<Button
variant="outline"
size="sm"
onClick={() => toggleMarketplaceFilter('no')}
className={`bg-white hover:bg-gray-100 min-w-[100px] ${
marketplaceFilter.includes('no') ? 'bg-green-600 text-white hover:bg-green-700' : ''
}`}
>
Not Listed
</Button>
</div>
</div>
</div>
</div>

{/* Table */}
<div className="w-full">
<Table>
<TableHeader className="bg-gray-800 [&_tr]:border-0">
<TableRow className="hover:bg-gray-800">
<TableHead
className="text-white cursor-pointer"
onClick={() => handleSort('name')}
>
<div className="flex items-center gap-2">
Name
{getSortIcon('name')}
</div>
</TableHead>
<TableHead
className="text-white cursor-pointer"
onClick={() => handleSort('description')}
>
<div className="flex items-center gap-2">
Description
{getSortIcon('description')}
</div>
</TableHead>
<TableHead
className="text-white cursor-pointer"
onClick={() => handleSort('state')}
>
<div className="flex items-center gap-2">
State
{getSortIcon('state')}
</div>
</TableHead>
<TableHead
className="text-white cursor-pointer"
onClick={() => handleSort('listedOnMarketplace')}
>
<div className="flex items-center gap-2">
Listed on marketplace
{getSortIcon('listedOnMarketplace')}
</div>
</TableHead>
<TableHead className="text-white w-[200px]"></TableHead>
</TableRow>
</TableHeader>
<TableBody>
{filteredAndSortedItems.map((item, index) => (
<TableRow key={index}>
<TableCell className="font-medium">{item.name}</TableCell>
<TableCell>{item.description}</TableCell>
<TableCell>
<span className={`px-2 py-1 rounded-full text-xs font-medium ${
item.state === 'active' ? 'bg-green-100 text-green-700' :
item.state === 'pending' ? 'bg-yellow-100 text-yellow-700' :
'bg-gray-100 text-gray-700'
}`}>
{item.state}
</span>
</TableCell>
<TableCell>
<span className={`px-2 py-1 rounded-full text-xs font-medium ${
item.listedOnMarketplace === 'yes' ? 'bg-blue-100 text-blue-700' : 'bg-gray-100 text-gray-700'
}`}>
{item.listedOnMarketplace}
</span>
</TableCell>
<TableCell>
<div className="flex justify-around gap-2">
<Button
variant="outline"
size="sm"
disabled={item.listedOnMarketplace === 'yes'}
>
Sell
</Button>
<Button variant="outline" size="sm">
View results
</Button>
</div>
</TableCell>
</TableRow>
))}
{filteredAndSortedItems.length === 0 && (
<TableRow>
<TableCell colSpan={5} className="h-24 text-center">
No results found.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
</Card>
</div>
)
}
31 changes: 24 additions & 7 deletions ntc-web/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,25 @@
@tailwind components;
@tailwind utilities;

body {
font-family: Arial, Helvetica, sans-serif;
}

@layer base {
@font-face {
font-family: "Visby";
src: url("/fonts/VisbyRoundCF-Regular.woff2");
font-weight: normal;
}

@font-face {
font-family: "Visby";
src: url("/fonts/VisbyRoundCF-Medium.woff2");
font-weight: 500;
}

@font-face {
font-family: "Visby";
src: url("/fonts/VisbyRoundCF-Bold.woff2");
font-weight: bold;
}

:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
Expand Down Expand Up @@ -34,6 +48,7 @@ body {
--chart-5: 27 87% 67%;
--radius: 0.5rem;
}

.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
Expand All @@ -60,13 +75,15 @@ body {
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
}
}

@layer base {
* {
@apply border-border;
}

body {
font-family: Visby, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
@apply bg-background text-foreground;
}
}
}
Loading

0 comments on commit f3652f8

Please sign in to comment.