Skip to content

Commit a198cd6

Browse files
authored
Improve component logic and enhance user experience (#331)
1 parent 18ad100 commit a198cd6

132 files changed

Lines changed: 10394 additions & 3892 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ next-env.d.ts
3636
.sanity
3737
dist/
3838

39+
# lint/format caches
40+
.eslintcache
41+
node_modules/.cache/prettier/.prettier-cache
42+
3943
# backups
4044
*.tar.gz
4145
storybook-static/*

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ The project uses Chromatic for visual regression testing. PRs automatically trig
208208
- Prefer working code over lengthy examples.
209209
- Do not provide lengthy summaries.
210210
- Always run `pnpm run check` before committing changes.
211+
- A pre-commit hook runs `pnpm run check && pnpm run test` automatically. After cloning, run `pnpm exec simple-git-hooks` to activate it.
211212

212213
### Date and Time Handling
213214

README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,32 @@ To run TypeScript type checking:
7272
pnpm run typecheck
7373
```
7474

75+
To run all checks at once (typecheck, lint, knip, format — runs in parallel):
76+
77+
```bash
78+
pnpm run check
79+
```
80+
81+
ESLint and Prettier use `--cache` flags so subsequent runs only process changed files. First run after a clean clone takes ~40s; warm runs take ~5s.
82+
83+
## Git Hooks
84+
85+
This project uses [simple-git-hooks](https://github.com/toplenboren/simple-git-hooks) to run `pnpm run check` and `pnpm run test` before every commit.
86+
87+
After cloning the repo and installing dependencies, activate the hooks:
88+
89+
```bash
90+
pnpm exec simple-git-hooks
91+
```
92+
93+
To skip the hook for a one-off commit:
94+
95+
```bash
96+
SKIP_SIMPLE_GIT_HOOKS=1 git commit -m "wip"
97+
```
98+
99+
If the hook configuration in `package.json` changes, re-run `pnpm exec simple-git-hooks` to update.
100+
75101
## Sanity
76102

77103
Install the Sanity CLI:

examples/SponsorManagementExample.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
'use client'
77

88
import { api } from '@/lib/trpc/client'
9+
import { LoadingSpinner } from '@/components/LoadingSpinner'
910
import { useState } from 'react'
1011
import type { SponsorTierExisting, SponsorInput } from '@/lib/sponsor/types'
1112

@@ -86,7 +87,7 @@ export function SponsorManagement() {
8687
{/* Loading State */}
8788
{loadingSponsors && (
8889
<div className="py-8 text-center">
89-
<div className="mx-auto h-8 w-8 animate-spin rounded-full border-b-2 border-blue-600"></div>
90+
<LoadingSpinner color="blue" />
9091
<p className="mt-2 text-gray-600">Loading sponsors...</p>
9192
</div>
9293
)}

package.json

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@
88
"build": "next build",
99
"build:clean": "rm -rf .next && pnpm run build",
1010
"start": "next start",
11-
"check": "pnpm run typecheck && pnpm run lint && pnpm run knip && pnpm run format",
11+
"check": "concurrently -n typecheck,lint,knip,format -c blue,green,yellow,magenta --kill-others-on-fail \"pnpm run typecheck\" \"pnpm run lint\" \"pnpm run knip\" \"pnpm run format\"",
1212
"knip": "knip",
1313
"knip:fix": "knip --fix",
14-
"lint": "eslint .",
15-
"lint:fix": "eslint --fix .",
14+
"lint": "eslint --cache .",
15+
"lint:fix": "eslint --cache --fix .",
1616
"test": "jest --silent",
1717
"test:debug": "NODE_OPTIONS='--experimental-vm-modules' jest",
1818
"test:watch": "NODE_OPTIONS='--experimental-vm-modules' jest --watch",
1919
"test:badges": "jest --silent __tests__/lib/badge/",
20-
"format:check": "prettier --check .",
21-
"format": "prettier --write --list-different .",
20+
"format:check": "prettier --cache --check .",
21+
"format": "prettier --cache --write --list-different .",
2222
"typecheck": "tsc --noEmit",
2323
"storybook": "storybook dev -p 6006",
2424
"build-storybook": "storybook build",
@@ -122,6 +122,7 @@
122122
"playwright": "^1.58.2",
123123
"prettier": "^3.8.1",
124124
"prettier-plugin-tailwindcss": "^0.7.2",
125+
"simple-git-hooks": "^2.13.1",
125126
"storybook": "^10.2.8",
126127
"ts-jest": "^29.4.6",
127128
"ts-node": "^10.9.2",
@@ -133,5 +134,8 @@
133134
"workerDirectory": [
134135
"public"
135136
]
137+
},
138+
"simple-git-hooks": {
139+
"pre-commit": "pnpm run check && pnpm run test"
136140
}
137141
}

pnpm-lock.yaml

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/app/(admin)/admin/proposals/[id]/page.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ import { getConferenceForCurrentDomain } from '@/lib/conference/sanity'
55
import {
66
ProposalDetail,
77
ErrorDisplay,
8-
BackToProposalsButton,
98
ProposalReviewPanel,
109
AdminActionBar,
1110
ProposalPublishedContent,
1211
AudienceFeedbackPanel,
1312
} from '@/components/admin'
13+
import { BackLink } from '@/components/BackButton'
1414
import { getAuthSession } from '@/lib/auth'
1515
import { getProposalVideoUrl } from '@/lib/proposal/video'
1616

@@ -59,7 +59,9 @@ export default async function ProposalDetailPage({
5959
<div className="mx-auto max-w-4xl p-4 lg:p-0">
6060
<div className="mb-8">
6161
<div className="mb-4 flex items-center justify-between">
62-
<BackToProposalsButton />
62+
<BackLink fallbackUrl="/admin/proposals">
63+
Back to Proposals
64+
</BackLink>
6365

6466
<div className="flex items-center space-x-3">
6567
<div className="flex items-center text-sm text-gray-500 dark:text-gray-400">

src/app/(admin)/admin/settings/page.tsx

Lines changed: 7 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
WorkshopRegistrationSettings,
77
AdminPageHeader,
88
} from '@/components/admin'
9+
import { StatusBadge } from '@/components/StatusBadge'
910
import {
1011
CalendarIcon,
1112
GlobeAltIcon,
@@ -33,31 +34,6 @@ function isValidFormat(key: string): key is Format {
3334
return Object.values(Format).includes(key as Format)
3435
}
3536

36-
function Badge({
37-
children,
38-
variant = 'default',
39-
}: {
40-
children: React.ReactNode
41-
variant?: 'default' | 'success' | 'warning' | 'error'
42-
}) {
43-
const variants = {
44-
default: 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300',
45-
success:
46-
'bg-green-100 text-green-800 dark:bg-green-900/20 dark:text-green-400',
47-
warning:
48-
'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/20 dark:text-yellow-400',
49-
error: 'bg-red-100 text-red-800 dark:bg-red-900/20 dark:text-red-400',
50-
}
51-
52-
return (
53-
<span
54-
className={`inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ${variants[variant]}`}
55-
>
56-
{children}
57-
</span>
58-
)
59-
}
60-
6137
function InfoCard({
6238
title,
6339
children,
@@ -147,7 +123,7 @@ function FieldRow({
147123
: (item as NamedItem)?.title ||
148124
(item as NamedItem)?.name ||
149125
JSON.stringify(item)
150-
return <Badge key={idx}>{displayText}</Badge>
126+
return <StatusBadge key={idx} label={displayText} color="gray" />
151127
})}
152128
</div>
153129
) : (
@@ -189,7 +165,7 @@ function FieldRow({
189165
formatKey && isValidFormat(formatKey)
190166
? formats.get(formatKey) || formatKey
191167
: formatKey || 'Unknown Format'
192-
return <Badge key={idx}>{displayText}</Badge>
168+
return <StatusBadge key={idx} label={displayText} color="gray" />
193169
})}
194170
</div>
195171
) : (
@@ -422,9 +398,11 @@ export default async function AdminSettings() {
422398
{tier.title}
423399
</span>
424400
<div className="flex items-center space-x-2">
425-
{tier.soldOut && <Badge variant="error">Sold Out</Badge>}
401+
{tier.soldOut && (
402+
<StatusBadge label="Sold Out" color="red" />
403+
)}
426404
{tier.mostPopular && (
427-
<Badge variant="success">Popular</Badge>
405+
<StatusBadge label="Popular" color="green" />
428406
)}
429407
</div>
430408
</div>

src/app/(admin)/admin/tickets/companies/page.tsx

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
HomeIcon,
1010
} from '@heroicons/react/24/outline'
1111
import Link from 'next/link'
12+
import { EmptyState } from '@/components/EmptyState'
1213

1314
async function getTicketData(
1415
customerId: number,
@@ -302,15 +303,12 @@ export default async function CompaniesAdminPage() {
302303

303304
<div>
304305
{companyBreakdown.length === 0 ? (
305-
<div className="rounded-lg bg-white p-12 text-center shadow dark:bg-gray-900">
306-
<BuildingOfficeIcon className="mx-auto h-12 w-12 text-gray-400 dark:text-gray-500" />
307-
<h3 className="mt-2 text-sm font-semibold text-gray-900 dark:text-white">
308-
No companies found
309-
</h3>
310-
<p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
311-
No company information available in ticket orders.
312-
</p>
313-
</div>
306+
<EmptyState
307+
icon={BuildingOfficeIcon}
308+
title="No companies found"
309+
description="No company information available in ticket orders."
310+
className="rounded-lg bg-white p-12 shadow dark:bg-gray-900"
311+
/>
314312
) : (
315313
<div className="overflow-hidden rounded-lg bg-white shadow dark:bg-gray-900">
316314
<div className="overflow-x-auto">

src/app/(admin)/admin/tickets/orders/page.tsx

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
BuildingOfficeIcon,
1212
} from '@heroicons/react/24/outline'
1313
import Link from 'next/link'
14+
import { EmptyState } from '@/components/EmptyState'
1415

1516
async function getTicketData(
1617
customerId: number,
@@ -91,15 +92,12 @@ export default async function OrdersAdminPage() {
9192
</div>
9293

9394
{orders.length === 0 ? (
94-
<div className="py-12 text-center">
95-
<ShoppingBagIcon className="mx-auto h-12 w-12 text-gray-400 dark:text-gray-500" />
96-
<h3 className="mt-2 text-sm font-semibold text-gray-900 dark:text-white">
97-
No orders found
98-
</h3>
99-
<p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
100-
No tickets have been sold for this event yet.
101-
</p>
102-
</div>
95+
<EmptyState
96+
icon={ShoppingBagIcon}
97+
title="No orders found"
98+
description="No tickets have been sold for this event yet."
99+
className="py-12"
100+
/>
103101
) : (
104102
<OrdersTableWithSearch
105103
orders={orders}

0 commit comments

Comments
 (0)