Skip to content

Commit 01e91bf

Browse files
authored
Preserve Gigs tab in URL hash (#385)
1 parent 596ab11 commit 01e91bf

6 files changed

Lines changed: 48 additions & 14 deletions

File tree

apps/admin_dashboard/src/main.tsx

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ type View =
8282
| "audit"
8383
| "configuration"
8484
type SortDirection = "asc" | "desc"
85+
type GigTab = "gigs" | "leads"
8586

8687
type User = {
8788
subject: string
@@ -666,6 +667,19 @@ function detailIdFromPath(expectedView: "gigs" | "projects" = "gigs") {
666667
}
667668
}
668669

670+
function gigTabFromHash(hash = window.location.hash): GigTab {
671+
return hash.replace(/^#/, "") === "leads" ? "leads" : "gigs"
672+
}
673+
674+
function updateGigTabHash(tab: GigTab) {
675+
const hash = tab === "leads" ? "#leads" : "#gigs"
676+
window.history.replaceState(
677+
window.history.state,
678+
"",
679+
`${window.location.pathname}${window.location.search}${hash}`,
680+
)
681+
}
682+
669683
async function requestJson<T>(url: string, options: RequestInit = {}): Promise<T> {
670684
const method = String(options.method || "GET").toUpperCase()
671685
const headers = new Headers(options.headers)
@@ -908,7 +922,7 @@ function App() {
908922
const [gigQuery, setGigQuery] = useState("")
909923
const [gigIncludeHistorical, setGigIncludeHistorical] = useState(false)
910924
const [gigLimit, setGigLimit] = useState(100)
911-
const [activeGigTab, setActiveGigTab] = useState<"gigs" | "leads">("gigs")
925+
const [activeGigTab, setActiveGigTab] = useState<GigTab>(gigTabFromHash)
912926
const [gigLeadStatus, setGigLeadStatus] = useState("pending")
913927
const [projectQuery, setProjectQuery] = useState("")
914928
const [projectStatus, setProjectStatus] = useState(initialProjectDetailId ? "" : "Open")
@@ -975,6 +989,7 @@ function App() {
975989
if (normalized !== "projects") setSelectedProjectId("")
976990
if (normalized === "gigs" && push) setSelectedGigId("")
977991
if (normalized === "projects" && push) setSelectedProjectId("")
992+
if (normalized === "gigs") setActiveGigTab(push ? "gigs" : gigTabFromHash())
978993
setViewState(normalized)
979994
if (push) {
980995
window.history.pushState({ view: normalized }, "", routes[normalized])
@@ -984,6 +999,11 @@ function App() {
984999
}
9851000
navigateRef.current = navigate
9861001

1002+
function selectGigTab(tab: GigTab) {
1003+
setActiveGigTab(tab)
1004+
updateGigTabHash(tab)
1005+
}
1006+
9871007
function crmContactUrl(contactId?: string) {
9881008
if (!crmBaseUrl || !contactId) return ""
9891009
return `${crmBaseUrl}/#Contact/view/${encodeURIComponent(contactId)}`
@@ -1717,7 +1737,7 @@ function App() {
17171737
},
17181738
)
17191739
showToast("Posted lead to Discord", "ok")
1720-
setActiveGigTab("gigs")
1740+
selectGigTab("gigs")
17211741
setGigStatus("")
17221742
setGigQuery("")
17231743
await loadGigLeads()
@@ -2344,6 +2364,12 @@ function App() {
23442364
return () => window.removeEventListener("popstate", onPopState)
23452365
}, [])
23462366

2367+
useEffect(() => {
2368+
const onHashChange = () => setActiveGigTab(gigTabFromHash())
2369+
window.addEventListener("hashchange", onHashChange)
2370+
return () => window.removeEventListener("hashchange", onHashChange)
2371+
}, [])
2372+
23472373
useEffect(() => {
23482374
if (!toast.message) return undefined
23492375
const timeout = window.setTimeout(() => setToast({ message: "" }), 4500)
@@ -2776,7 +2802,7 @@ function App() {
27762802
canIncludeHistorical={can("people:read")}
27772803
crmContactUrl={crmContactUrl}
27782804
crmAttachmentUrl={crmAttachmentUrl}
2779-
setActiveTab={setActiveGigTab}
2805+
setActiveTab={selectGigTab}
27802806
setStatus={setGigStatus}
27812807
setQuery={setGigQuery}
27822808
setLeadStatus={setGigLeadStatus}

apps/api/src/five08/backend/static/dashboard/.vite/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"index.html": {
3-
"file": "assets/index-LL0oAOC_.js",
3+
"file": "assets/index-_nigGMGP.js",
44
"name": "index",
55
"src": "index.html",
66
"isEntry": true,

apps/api/src/five08/backend/static/dashboard/assets/index-LL0oAOC_.js

Lines changed: 0 additions & 9 deletions
This file was deleted.

apps/api/src/five08/backend/static/dashboard/assets/index-_nigGMGP.js

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

apps/api/src/five08/backend/static/dashboard/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<meta charset="UTF-8" />
55
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
66
<title>508 Operations Dashboard</title>
7-
<script type="module" crossorigin src="/dashboard/assets/index-LL0oAOC_.js"></script>
7+
<script type="module" crossorigin src="/dashboard/assets/index-_nigGMGP.js"></script>
88
<link rel="stylesheet" crossorigin href="/dashboard/assets/index-2UypYUrJ.css">
99
</head>
1010
<body>

tests/integration/test_dashboard_playwright.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -862,7 +862,15 @@ def sync_route(route: Any) -> None:
862862
"status=" not in urlparse(url).query for url in gig_list_requests
863863
)
864864
page.locator("#gigLeadsTab").click()
865+
expect(page).to_have_url(f"{dashboard_server}/dashboard/gigs#leads")
866+
page.reload()
865867
page.get_by_text("Contract React Build").wait_for()
868+
page.get_by_role("link", name="People").click()
869+
expect(page).to_have_url(f"{dashboard_server}/dashboard/people")
870+
page.get_by_role("link", name="Gigs").click()
871+
expect(page).to_have_url(f"{dashboard_server}/dashboard/gigs")
872+
expect(page.locator("#gigsTab")).to_have_attribute("aria-pressed", "true")
873+
page.locator("#gigLeadsTab").click()
866874
expect(
867875
page.get_by_text("Full-time or part-time / contract · LLM")
868876
).to_be_visible()

0 commit comments

Comments
 (0)