-
-
Notifications
You must be signed in to change notification settings - Fork 213
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
clients/issues: fix 404 on issue pages
- Loading branch information
1 parent
33cc68b
commit f7cb8dc
Showing
3 changed files
with
289 additions
and
0 deletions.
There are no files selected for viewing
91 changes: 91 additions & 0 deletions
91
clients/apps/web/src/app/(main)/[organization]/[repo]/issues/(create)/ClientPage.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
'use client' | ||
|
||
import WhiteCard from '@/components/Cards/WhiteCard' | ||
import FAQ from '@/components/Pledge/FAQ' | ||
import HowItWorks from '@/components/Pledge/HowItWorks' | ||
import IssueCard from '@/components/Pledge/IssueCard' | ||
import PledgeCheckoutPanel from '@/components/Pledge/PledgeCheckoutPanel' | ||
import { usePostHog } from '@/hooks/posthog' | ||
import { Issue, Organization, Pledger, RewardsSummary } from '@polar-sh/api' | ||
import Banner from '@polar-sh/ui/components/molecules/Banner' | ||
import { useEffect, useState } from 'react' | ||
|
||
const ClientPage = ({ | ||
issue, | ||
organization, | ||
htmlBody, | ||
pledgers, | ||
gotoURL, | ||
rewards, | ||
}: { | ||
issue: Issue | ||
organization: Organization | ||
htmlBody?: string | ||
pledgers: Pledger[] | ||
gotoURL?: string | ||
rewards?: RewardsSummary | ||
}) => { | ||
const posthog = usePostHog() | ||
|
||
const [amount, setAmount] = useState(0) | ||
const onAmountChange = (amount: number) => { | ||
setAmount(amount) | ||
} | ||
|
||
useEffect(() => { | ||
if (issue) { | ||
posthog.capture('storefront:issues:page:view', { | ||
organization_id: organization.id, | ||
organization_name: organization.slug, | ||
repository_id: issue.repository.id, | ||
repository_name: issue.repository.name, | ||
issue_id: issue.id, | ||
issue_number: issue.number, | ||
}) | ||
} | ||
}, [issue, organization]) | ||
|
||
return ( | ||
<> | ||
{issue.repository.is_private && ( | ||
<div className="w-full"> | ||
<Banner color="muted"> | ||
This is an issue in a private repository. Only logged in users that | ||
are members of {issue.repository.organization.name} can see it. | ||
</Banner> | ||
</div> | ||
)} | ||
|
||
<div className="grid w-full grid-cols-1 gap-12 lg:grid-cols-2"> | ||
{/* Left side */} | ||
<div className="mt-12"> | ||
<IssueCard | ||
issue={issue} | ||
organization={organization} | ||
htmlBody={htmlBody} | ||
pledgers={pledgers} | ||
currentPledgeAmount={amount} | ||
rewards={rewards} | ||
/> | ||
</div> | ||
|
||
{/* Right side */} | ||
<div> | ||
<WhiteCard padding> | ||
<PledgeCheckoutPanel | ||
issue={issue} | ||
organization={organization} | ||
gotoURL={gotoURL} | ||
onAmountChange={onAmountChange} | ||
/> | ||
</WhiteCard> | ||
</div> | ||
</div> | ||
|
||
<HowItWorks /> | ||
<FAQ /> | ||
</> | ||
) | ||
} | ||
|
||
export default ClientPage |
140 changes: 140 additions & 0 deletions
140
clients/apps/web/src/app/(main)/[organization]/[repo]/issues/(create)/page.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
import { getServerSideAPI } from '@/utils/api/serverside' | ||
import { resolveIssuePath } from '@/utils/issue' | ||
import { organizationPageLink } from '@/utils/nav' | ||
import { Pledger, ResponseError, RewardsSummary } from '@polar-sh/api' | ||
import { Metadata } from 'next' | ||
import { notFound, redirect } from 'next/navigation' | ||
import ClientPage from './ClientPage' | ||
|
||
const cacheConfig = { | ||
cache: 'no-store', | ||
} as const | ||
|
||
export async function generateMetadata({ | ||
params, | ||
}: { | ||
params: { organization: string; repo: string; number: string } | ||
}): Promise<Metadata> { | ||
const api = getServerSideAPI() | ||
const resolvedIssueOrganization = await resolveIssuePath( | ||
api, | ||
params.organization, | ||
params.repo, | ||
params.number, | ||
cacheConfig, | ||
) | ||
|
||
if (!resolvedIssueOrganization) { | ||
notFound() | ||
} | ||
|
||
const [issue, organization] = resolvedIssueOrganization | ||
|
||
// Redirect to the actual Polar organization if resolved from external organization | ||
if (organization.slug !== params.organization) { | ||
redirect( | ||
organizationPageLink( | ||
organization, | ||
`${issue.repository.name}/issues/${issue.number}`, | ||
), | ||
) | ||
} | ||
|
||
return { | ||
title: `Fund: ${issue.title}`, // " | Polar is added by the template" | ||
openGraph: { | ||
title: `Fund: ${issue.title}`, | ||
description: `${issue.repository.organization.name} seeks funding for ${issue.title} Polar`, | ||
type: 'website', | ||
images: [ | ||
{ | ||
url: `https://polar.sh/og?org=${issue.repository.organization.name}&repo=${issue.repository.name}&number=${issue.number}`, | ||
width: 1200, | ||
height: 630, | ||
}, | ||
], | ||
}, | ||
twitter: { | ||
images: [ | ||
{ | ||
url: `https://polar.sh/og?org=${issue.repository.organization.name}&repo=${issue.repository.name}&number=${issue.number}`, | ||
width: 1200, | ||
height: 630, | ||
alt: `${issue.repository.organization.name} seeks funding for ${issue.title} on Polar`, | ||
}, | ||
], | ||
card: 'summary_large_image', | ||
title: `${issue.repository.organization.name} seeks funding for ${issue.title}`, | ||
description: `${issue.repository.organization.name} seeks funding for ${issue.title} on Polar`, | ||
}, | ||
} | ||
} | ||
|
||
export default async function Page({ | ||
params, | ||
}: { | ||
params: { organization: string; repo: string; number: string } | ||
}) { | ||
const api = getServerSideAPI() | ||
const resolvedIssueOrganization = await resolveIssuePath( | ||
api, | ||
params.organization, | ||
params.repo, | ||
params.number, | ||
cacheConfig, | ||
) | ||
|
||
if (!resolvedIssueOrganization) { | ||
notFound() | ||
} | ||
|
||
const [issue, organization] = resolvedIssueOrganization | ||
|
||
// Redirect to the actual Polar organization if resolved from external organization | ||
if (organization.slug !== params.organization) { | ||
redirect( | ||
organizationPageLink( | ||
organization, | ||
`${issue.repository.name}/issues/${issue.number}`, | ||
), | ||
) | ||
} | ||
|
||
let issueHTMLBody: string | undefined | ||
let pledgers: Pledger[] = [] | ||
let rewards: RewardsSummary | undefined | ||
|
||
try { | ||
const [bodyResponse, pledgeSummary, rewardsSummary] = await Promise.all([ | ||
api.issues.getBody({ id: issue.id }, { next: { revalidate: 60 } }), // Cache for 60s | ||
api.pledges.summary({ issueId: issue.id }, cacheConfig), | ||
api.rewards.summary({ issueId: issue.id }, cacheConfig), | ||
]) | ||
|
||
issueHTMLBody = bodyResponse | ||
pledgers = pledgeSummary.pledges | ||
.map(({ pledger }) => pledger) | ||
.filter((p): p is Pledger => !!p) | ||
rewards = rewardsSummary | ||
} catch (e) { | ||
if (e instanceof ResponseError && e.response.status === 404) { | ||
notFound() | ||
} | ||
} | ||
|
||
// Closed issue, redirect to donation instead if linked organization | ||
if (issue.issue_closed_at) { | ||
redirect(organizationPageLink(organization, `donate?issue_id=${issue.id}`)) | ||
} | ||
|
||
return ( | ||
<ClientPage | ||
issue={issue} | ||
organization={organization} | ||
htmlBody={issueHTMLBody} | ||
pledgers={pledgers} | ||
rewards={rewards} | ||
gotoURL={undefined} | ||
/> | ||
) | ||
} |
58 changes: 58 additions & 0 deletions
58
clients/apps/web/src/app/(main)/[organization]/[repo]/issues/status/page.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import Status from '@/components/Pledge/Status' | ||
import { api } from '@/utils/api' | ||
import { resolveRepositoryPath } from '@/utils/repository' | ||
import { Pledge, ResponseError } from '@polar-sh/api' | ||
import { notFound } from 'next/navigation' | ||
|
||
const cacheConfig = { | ||
cache: 'no-store', | ||
} as const | ||
|
||
export default async function Page({ | ||
params, | ||
searchParams, | ||
}: { | ||
params: { organization: string; repo: string; number: string } | ||
searchParams: { [key: string]: string | string[] | undefined } | ||
}) { | ||
const resolvedRepositoryOrganization = await resolveRepositoryPath( | ||
api, | ||
params.organization, | ||
params.repo, | ||
cacheConfig, | ||
) | ||
|
||
if (!resolvedRepositoryOrganization) { | ||
notFound() | ||
} | ||
|
||
const [, organization] = resolvedRepositoryOrganization | ||
|
||
const paymentIntentId = searchParams['payment_intent_id'] | ||
if (typeof paymentIntentId !== 'string') { | ||
notFound() | ||
} | ||
|
||
let pledge: Pledge | ||
|
||
try { | ||
pledge = await api.pledges.create({ | ||
body: { | ||
payment_intent_id: paymentIntentId, | ||
}, | ||
}) | ||
} catch (e) { | ||
if (e instanceof ResponseError) { | ||
if (e.response.status === 404) { | ||
notFound() | ||
} | ||
} | ||
throw e | ||
} | ||
|
||
const email = searchParams['email'] as string | undefined | ||
|
||
// TODO: Handle different statuses than success... #happy-path-alpha-programming | ||
|
||
return <Status pledge={pledge} organization={organization} email={email} /> | ||
} |