Skip to content

Commit 9f6349f

Browse files
committed
Adds links to search results.
- Adds href links to search results based on content type and uid. - Disable static export in next.config.ts to allow for dynamic routing. - Renames officer page to use dynamic routing with uid.
1 parent f974536 commit 9f6349f

File tree

4 files changed

+119
-60
lines changed

4 files changed

+119
-60
lines changed
Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,37 @@ import { useEffect, useState } from "react"
44
import { useAuth } from "@/providers/AuthProvider"
55
import { apiFetch } from "@/utils/apiFetch"
66
import API_ROUTES, { apiBaseUrl } from "@/utils/apiRoutes"
7-
import { useSearchParams } from "next/navigation"
7+
import { useParams } from "next/navigation"
88
import { Officer } from "@/utils/api"
99
import DetailsLayout from "@/components/Details/DetailsLayout"
1010
import IdentityCard from "@/components/Details/IdentityCard"
1111
import DetailsTabs from "@/components/Details/DetailsTabs"
1212
import ContentDetails from "@/components/Details/ContentDetails"
1313

1414
export default function OfficerDetailsPage() {
15-
const searchParams = useSearchParams()
16-
const uid = searchParams.get("uid")
15+
const params = useParams<{ uid: string }>()
16+
const uid = params.uid
17+
1718
const [officer, setOfficer] = useState<Officer | null>(null)
1819
const { accessToken } = useAuth()
1920
const [loading, setLoading] = useState(true)
2021

2122
useEffect(() => {
22-
if (accessToken && uid) {
23-
apiFetch(
24-
`${apiBaseUrl}${API_ROUTES.officers.profile(uid)}?include=employment&include=allegations`,
25-
{
26-
headers: {
27-
Authorization: `Bearer ${accessToken}`
28-
}
23+
if (!accessToken || !uid) return
24+
25+
setLoading(true)
26+
27+
apiFetch(
28+
`${apiBaseUrl}${API_ROUTES.officers.profile(uid)}?include=employment&include=allegations`,
29+
{
30+
headers: {
31+
Authorization: `Bearer ${accessToken}`
2932
}
30-
)
31-
.then((res) => res.json())
32-
.then((data) => setOfficer(data.results || data))
33-
.finally(() => setLoading(false))
34-
}
33+
}
34+
)
35+
.then((res) => res.json())
36+
.then((data) => setOfficer(data.results || data))
37+
.finally(() => setLoading(false))
3538
}, [accessToken, uid])
3639

3740
if (loading) return <div>Loading...</div>
@@ -43,4 +46,4 @@ export default function OfficerDetailsPage() {
4346
<DetailsTabs {...officer} />
4447
</DetailsLayout>
4548
)
46-
}
49+
}

frontend/app/profile/edit/EditProfilePage.module.css

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929

3030
.bioCount {
3131
font-size: 0.875rem;
32-
color: #666;
32+
color: #566;
3333
margin: 0;
3434
}
3535

Lines changed: 99 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
"use client"
2-
import { Tab, Tabs, Box, CardHeader, Typography } from "@mui/material"
2+
3+
import Link from "next/link"
4+
import {
5+
Tab,
6+
Tabs,
7+
Box,
8+
Card,
9+
CardHeader,
10+
CardActionArea,
11+
Typography
12+
} from "@mui/material"
313
import React from "react"
414
import { SearchResponse } from "@/utils/api"
515

@@ -10,6 +20,23 @@ type SearchResultsProps = {
1020
updateTab: (val: number) => void
1121
}
1222

23+
const getResultHref = (result: SearchResponse) => {
24+
switch (result.content_type) {
25+
case "Officer":
26+
return `/officer/${result.uid}`
27+
case "Agency":
28+
return `/agency/${result.uid}`
29+
case "Unit":
30+
return `/unit/${result.uid}`
31+
case "Complaint":
32+
return `/complaint/${result.uid}`
33+
case "Litigation":
34+
return `/litigation/${result.uid}`
35+
default:
36+
return "#"
37+
}
38+
}
39+
1340
const SearchResults = ({ total, results, tab, updateTab }: SearchResultsProps) => {
1441
return (
1542
<>
@@ -31,51 +58,80 @@ const SearchResults = ({ total, results, tab, updateTab }: SearchResultsProps) =
3158
<Tab key="litigation" label="Litigation" />
3259
</Tabs>
3360
</Box>
61+
3462
<Box sx={{ p: 3 }}>
35-
<Typography sx={{ marginBottom: "1rem", fontWeight: "bold" }}>{total} results</Typography>
63+
<Typography sx={{ mb: 2, fontWeight: "bold" }}>{total} results</Typography>
64+
3665
<CustomTabPanel value={tab} index={tab}>
37-
{results.map((result) => (
38-
<CardHeader
66+
{results.map((result, idx) => (
67+
<Card
3968
key={result.uid}
40-
title={result.title}
41-
subheader={result.subtitle}
42-
slotProps={{ subheader: { fontWeight: "bold", color: "#000" } }}
43-
action={
44-
<Box>
45-
<Box sx={{ display: "flex", gap: "1rem" }}>
46-
<span style={{ fontSize: "14px", color: "#454C54", margin: "0 0 1rem 0" }}>
47-
{result.details}
48-
</span>
49-
</Box>
50-
<Box sx={{ display: "flex", gap: "1rem" }}>
51-
<span style={{ fontSize: "12px", color: "#666" }}>{result.content_type}</span>
52-
<span style={{ fontSize: "12px", color: "#666" }}>{result.source}</span>
53-
<span style={{ fontSize: "12px", color: "#666" }}>{result.last_updated}</span>
54-
</Box>
55-
</Box>
56-
}
69+
variant="outlined"
5770
sx={{
58-
flexDirection: "column",
59-
alignItems: "flex-start",
60-
gap: "0.5rem",
61-
border: "1px solid #ddd",
62-
borderBottom: "none",
63-
":first-of-type": {
64-
borderTopLeftRadius: "4px",
65-
borderTopRightRadius: "4px"
66-
},
67-
":last-of-type": {
68-
borderBottomLeftRadius: "4px",
69-
borderBottomRightRadius: "4px",
70-
borderBottom: "1px solid #ddd"
71-
},
72-
"& .MuiCardHeader-content": {
73-
overflow: "hidden"
74-
},
75-
paddingInline: "4.5rem",
76-
paddingBlock: "2rem"
71+
borderBottomLeftRadius: idx === results.length - 1 ? "4px" : 0,
72+
borderBottomRightRadius: idx === results.length - 1 ? "4px" : 0,
73+
borderTopLeftRadius: idx === 0 ? "4px" : 0,
74+
borderTopRightRadius: idx === 0 ? "4px" : 0,
75+
borderBottom: idx === results.length - 1 ? undefined : "none"
7776
}}
78-
/>
77+
>
78+
<CardActionArea
79+
component={Link}
80+
href={getResultHref(result)}
81+
sx={{
82+
display: "block",
83+
textAlign: "left",
84+
"&:hover": {
85+
backgroundColor: "#f8f8f8"
86+
}
87+
}}
88+
>
89+
<CardHeader
90+
title={result.title}
91+
subheader={result.subtitle}
92+
slotProps={{ subheader: { fontWeight: "bold", color: "#000" } }}
93+
action={
94+
<Box>
95+
<Box sx={{ display: "flex", gap: "1rem" }}>
96+
<span
97+
style={{
98+
fontSize: "14px",
99+
color: "#454C54",
100+
margin: "0 0 1rem 0"
101+
}}
102+
>
103+
{Array.isArray(result.details)
104+
? result.details.join(", ")
105+
: result.details}
106+
</span>
107+
</Box>
108+
109+
<Box sx={{ display: "flex", gap: "1rem" }}>
110+
<span style={{ fontSize: "12px", color: "#566" }}>
111+
{result.content_type}``
112+
</span>
113+
<span style={{ fontSize: "12px", color: "#566" }}>
114+
{result.source}
115+
</span>
116+
<span style={{ fontSize: "12px", color: "#566" }}>
117+
{result.last_updated}
118+
</span>
119+
</Box>
120+
</Box>
121+
}
122+
sx={{
123+
flexDirection: "column",
124+
alignItems: "flex-start",
125+
gap: "0.5rem",
126+
"& .MuiCardHeader-content": {
127+
overflow: "hidden"
128+
},
129+
paddingInline: "4.5rem",
130+
paddingBlock: "2rem"
131+
}}
132+
/>
133+
</CardActionArea>
134+
</Card>
79135
))}
80136
</CustomTabPanel>
81137
</Box>
@@ -102,4 +158,5 @@ const CustomTabPanel = ({ children, value, index, ...other }: TabPanelProps) =>
102158
</div>
103159
)
104160
}
105-
export default SearchResults
161+
162+
export default SearchResults

frontend/next.config.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import type { NextConfig } from "next"
22

33
const nextConfig: NextConfig = {
44
/* config options here */
5-
output: "export"
65
}
76

87
export default nextConfig

0 commit comments

Comments
 (0)