Skip to content

Commit 41da94d

Browse files
authored
chore: add infobox (#205)
* chore: installed react-icons * chore: add none to celo funding sources * chore: implemented BioInfo and InfoBox * chore: added required prop to form section
1 parent 361c456 commit 41da94d

File tree

10 files changed

+179
-53
lines changed

10 files changed

+179
-53
lines changed

bun.lockb

401 Bytes
Binary file not shown.

package.json

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
"react-day-picker": "^8.10.0",
5858
"react-dom": "18.2.0",
5959
"react-hook-form": "^7.49.3",
60+
"react-icons": "^5.4.0",
6061
"react-markdown": "^9.0.1",
6162
"react-number-format": "^5.3.1",
6263
"react-use": "^17.5.0",

src/components/ui/Form.tsx

+6-1
Original file line numberDiff line numberDiff line change
@@ -282,14 +282,19 @@ export function FieldArray<S extends z.Schema>({
282282
export function FormSection({
283283
title,
284284
description,
285+
required,
285286
children,
286287
}: {
287288
title: ReactNode | string;
288289
description: ReactNode | string;
290+
required?: boolean;
289291
} & ComponentProps<"section">) {
290292
return (
291293
<section className="mb-8">
292-
<h3 className="mb-1 text-xl font-semibold">{title}</h3>
294+
<h3 className="mb-1 text-xl font-semibold">
295+
{title}
296+
{required && <span className="text-red-300">*</span>}
297+
</h3>
293298
<p className="mb-4 leading-loose text-gray-600 dark:text-gray-400">
294299
{description}
295300
</p>

src/features/applications/components/ApplicationForm.tsx

+6-15
Original file line numberDiff line numberDiff line change
@@ -163,11 +163,8 @@ export function ApplicationForm({ address }: { address: Address }) {
163163
</FormSection>
164164

165165
<FormSection
166-
title={
167-
<>
168-
Contribution links <span className="text-red-300">*</span>
169-
</>
170-
}
166+
required
167+
title="Contribution links"
171168
description="Where can we find your contributions?"
172169
>
173170
<FieldArray
@@ -205,11 +202,8 @@ export function ApplicationForm({ address }: { address: Address }) {
205202
</FormSection>
206203

207204
<FormSection
208-
title={
209-
<>
210-
Impact metrics <span className="text-red-300">*</span>
211-
</>
212-
}
205+
required
206+
title="Impact metrics"
213207
description="What kind of impact has your project made?"
214208
>
215209
<FieldArray
@@ -247,11 +241,8 @@ export function ApplicationForm({ address }: { address: Address }) {
247241
</FormSection>
248242

249243
<FormSection
250-
title={
251-
<>
252-
Funding sources <span className="text-red-300">*</span>
253-
</>
254-
}
244+
required
245+
title="Funding sources"
255246
description="From what sources have you received funding?"
256247
>
257248
<FieldArray

src/features/applications/components/CeloApplicationForm.tsx

+9-19
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ import {
2222
import {
2323
CeloApplicationSchema,
2424
ProfileSchema,
25+
celoFundingSourceTypes,
2526
contributionTypes,
26-
fundingSourceTypes,
2727
} from "../types";
2828
import { useCreateApplication } from "../hooks/useCreateApplication";
2929
import { Tag } from "~/components/ui/Tag";
@@ -183,7 +183,7 @@ export function CeloApplicationForm({ address }: { address: Address }) {
183183
<ImpactTags />
184184

185185
<FormSection
186-
title={<>Contribution</>}
186+
title="Contribution"
187187
description={
188188
<span>
189189
Highlight the overall contributions and specific actions you
@@ -224,11 +224,8 @@ export function CeloApplicationForm({ address }: { address: Address }) {
224224
</FormControl>
225225
</FormSection>
226226
<FormSection
227-
title={
228-
<>
229-
Contribution links <span className="text-red-300">*</span>
230-
</>
231-
}
227+
required
228+
title="Contribution links"
232229
description="Where can we find your contributions?"
233230
>
234231
<FieldArray
@@ -268,7 +265,7 @@ export function CeloApplicationForm({ address }: { address: Address }) {
268265
</FormSection>
269266

270267
<FormSection
271-
title={<>Impact</>}
268+
title="Impact"
272269
description={
273270
<span>
274271
Highlight how your contributions have positively impacted the
@@ -313,11 +310,8 @@ export function CeloApplicationForm({ address }: { address: Address }) {
313310
</FormSection>
314311

315312
<FormSection
316-
title={
317-
<>
318-
Impact metrics <span className="text-red-300">*</span>
319-
</>
320-
}
313+
required
314+
title="Impact metrics"
321315
description="What kind of impact has your project made?"
322316
>
323317
<FieldArray
@@ -354,11 +348,7 @@ export function CeloApplicationForm({ address }: { address: Address }) {
354348
/>
355349
</FormSection>
356350
<FormSection
357-
title={
358-
<>
359-
Funding sources <span className="text-red-300">*</span>
360-
</>
361-
}
351+
title="Funding sources"
362352
description="From what sources have you received funding?"
363353
>
364354
<FieldArray
@@ -395,7 +385,7 @@ export function CeloApplicationForm({ address }: { address: Address }) {
395385
required
396386
>
397387
<Select>
398-
{Object.entries(fundingSourceTypes).map(
388+
{Object.entries(celoFundingSourceTypes).map(
399389
([value, label]) => (
400390
<option key={value} value={value}>
401391
{label}

src/features/applications/components/DripsApplicationForm.tsx

+6-15
Original file line numberDiff line numberDiff line change
@@ -190,11 +190,8 @@ export function DripsApplicationForm({ address }: { address: Address }) {
190190
</FormSection>
191191

192192
<FormSection
193-
title={
194-
<>
195-
Contribution links <span className="text-red-300">*</span>
196-
</>
197-
}
193+
required
194+
title="Contribution links"
198195
description="Where can we find your contributions?"
199196
>
200197
<FieldArray
@@ -232,11 +229,8 @@ export function DripsApplicationForm({ address }: { address: Address }) {
232229
</FormSection>
233230

234231
<FormSection
235-
title={
236-
<>
237-
Impact metrics <span className="text-red-300">*</span>
238-
</>
239-
}
232+
required
233+
title="Impact metrics"
240234
description="What kind of impact has your project made?"
241235
>
242236
<FieldArray
@@ -274,11 +268,8 @@ export function DripsApplicationForm({ address }: { address: Address }) {
274268
</FormSection>
275269

276270
<FormSection
277-
title={
278-
<>
279-
Funding sources <span className="text-red-300">*</span>
280-
</>
281-
}
271+
required
272+
title="Funding sources"
282273
description="From what sources have you received funding?"
283274
>
284275
<FieldArray

src/features/applications/types/index.ts

+15
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ export const fundingSourceTypes = {
2929
OTHER: "Other",
3030
} as const;
3131

32+
export const celoFundingSourceTypes = {
33+
...fundingSourceTypes,
34+
NONE: "None",
35+
} as const;
36+
3237
export const ApplicationSchema = z.object({
3338
name: z.string().min(3),
3439
bio: z.string().min(3),
@@ -74,6 +79,16 @@ export const DripsApplicationSchema = z.object({
7479

7580
export const CeloApplicationSchema = z.object({
7681
...ApplicationSchema.shape,
82+
fundingSources: z
83+
.array(
84+
z.object({
85+
description: z.string().min(3),
86+
amount: z.number(),
87+
currency: z.string().min(3).max(4),
88+
type: z.nativeEnum(reverseKeys(celoFundingSourceTypes)),
89+
}),
90+
)
91+
.min(1),
7792
twitterHandle: z.string().optional(),
7893
farcasterHandle: z.string().optional(),
7994
telegramHandle: z.string().optional(),
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { Markdown } from "~/components/ui/Markdown";
2+
import { type Application } from "~/features/applications/types";
3+
import { InfoBox, type InfoBoxProps } from "./InfoBox";
4+
5+
type Props = {
6+
project?: Application & {
7+
githubUrl?: string;
8+
twitterHandle?: string;
9+
farcasterHandle?: string;
10+
telegramHandle?: string;
11+
githubHandle?: string;
12+
emailHandle?: string;
13+
country?: string;
14+
};
15+
};
16+
17+
export default function BioInfo({ project }: Props) {
18+
const {
19+
bio,
20+
twitterHandle,
21+
farcasterHandle,
22+
telegramHandle,
23+
githubHandle,
24+
emailHandle,
25+
country,
26+
} = project ?? {};
27+
28+
const elements: InfoBoxProps["elements"] = [
29+
{ type: "country", value: country },
30+
{ type: "email", value: emailHandle },
31+
{ type: "twitter", value: twitterHandle },
32+
{ type: "farcaster", value: farcasterHandle },
33+
{ type: "telegram", value: telegramHandle },
34+
{ type: "github", value: githubHandle },
35+
];
36+
37+
const showInfoBox = elements.some(({ value }) => value);
38+
39+
if (!showInfoBox) return <Markdown>{bio}</Markdown>;
40+
41+
return (
42+
<div className="mb-4 flex flex-col gap-4 md:flex-row">
43+
<div className="md:w-2/3">
44+
<Markdown>{bio}</Markdown>
45+
</div>
46+
<div className="md:w-1/3">
47+
<InfoBox label="Info" elements={elements} />
48+
</div>
49+
</div>
50+
);
51+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { ExternalLink } from "~/components/ui/Link";
2+
import {
3+
SiFarcaster as Farcaster,
4+
SiTelegram as Telegram,
5+
} from "react-icons/si";
6+
import { FaXTwitter as Twitter } from "react-icons/fa6";
7+
import { LuGithub as Github, LuGlobe as Globe } from "react-icons/lu";
8+
import { MdOutlineMail as Mail } from "react-icons/md";
9+
import { type IconType } from "react-icons/lib";
10+
11+
const InfoItem = ({
12+
type,
13+
value,
14+
}: {
15+
type: "github" | "twitter" | "farcaster" | "telegram" | "email" | "country";
16+
value: string;
17+
}) => {
18+
const Icon: IconType | undefined = {
19+
github: Github,
20+
twitter: Twitter,
21+
farcaster: Farcaster,
22+
telegram: Telegram,
23+
email: Mail,
24+
country: Globe,
25+
}[type];
26+
27+
const sanitizedValue = value.startsWith("@") ? value.slice(1) : value;
28+
29+
const url =
30+
sanitizedValue.startsWith("http://") ||
31+
sanitizedValue.startsWith("https://")
32+
? sanitizedValue
33+
: {
34+
github: `https://github.com/${sanitizedValue}`,
35+
twitter: `https://x.com/${sanitizedValue}`,
36+
farcaster: `https://warpcast.com/${sanitizedValue}`,
37+
telegram: `https://t.me/${sanitizedValue}`,
38+
email: `mailto:${sanitizedValue}`,
39+
country: `https://www.google.com/maps/search/${sanitizedValue}`,
40+
}[type];
41+
42+
if (type === "country") {
43+
return (
44+
<div className="flex gap-2">
45+
<Icon className="mt-1 h-4 w-4" />
46+
{value}
47+
</div>
48+
);
49+
}
50+
51+
return (
52+
<ExternalLink href={url} className="flex gap-2 hover:underline">
53+
<Icon className="mt-1 h-4 w-4" />
54+
{value}
55+
</ExternalLink>
56+
);
57+
};
58+
59+
export interface InfoBoxProps {
60+
label: string;
61+
elements?: {
62+
type: "github" | "twitter" | "farcaster" | "telegram" | "email" | "country";
63+
value?: string;
64+
}[];
65+
}
66+
67+
export const InfoBox = ({ label, elements }: InfoBoxProps) => {
68+
const filteredElements = elements?.filter(({ value }) => value);
69+
return (
70+
<div className="rounded-xl border p-3 dark:border-gray-700">
71+
<div className="mb-2 font-bold tracking-wider text-gray-600 dark:text-gray-500">
72+
{label}
73+
</div>
74+
<div className="space-y-2">
75+
{filteredElements?.map(({ type, value }, i) => (
76+
<InfoItem key={i} type={type} value={value!} />
77+
))}
78+
</div>
79+
</div>
80+
);
81+
};

src/features/projects/components/ProjectDetails.tsx

+4-3
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import { NameENS } from "~/components/ENS";
1111
import { suffixNumber } from "~/utils/suffixNumber";
1212
import { useProjectMetadata } from "../hooks/useProjects";
1313
import { type Attestation } from "~/utils/fetchAttestations";
14-
import { Markdown } from "~/components/ui/Markdown";
1514
import { useRoundType } from "~/hooks/useRoundType";
15+
import BioInfo from "./BioInfo";
1616

1717
export default function ProjectDetails({
1818
attestation,
@@ -31,7 +31,7 @@ export default function ProjectDetails({
3131
const isCeloRound = roundType === "CELO";
3232
const isDripRound = roundType === "DRIP";
3333

34-
const { bio, websiteUrl, payoutAddress, fundingSources, githubUrl } =
34+
const { websiteUrl, payoutAddress, fundingSources, githubUrl } =
3535
metadata.data ?? {};
3636

3737
return (
@@ -74,7 +74,7 @@ export default function ProjectDetails({
7474
</div>
7575
</div>
7676
</div>
77-
<Markdown>{bio}</Markdown>
77+
<BioInfo project={metadata.data} />
7878
<div>
7979
<Heading as="h2" size="3xl">
8080
Impact statements
@@ -98,6 +98,7 @@ export default function ProjectDetails({
9898
GOVERNANCE_FUND: "Governance Fund",
9999
PARTNER_FUND: "Partner Fund",
100100
REVENUE: "Revenue",
101+
NONE: "None",
101102
}[source.type] ?? source.type;
102103
return (
103104
<div key={i} className="flex items-center gap-4">

0 commit comments

Comments
 (0)