1- import { GetServerSideProps , NextPage } from 'next'
1+ import { GlobeAltIcon } from '@heroicons/react/outline'
2+ import { Check } from 'lucide-react'
3+ import { GetServerSideProps } from 'next'
4+ import { NextSeo } from 'next-seo'
25import Image from 'next/image'
36import Link from 'next/link'
47import { useRouter } from 'next/router'
5- import { NextSeo } from 'next-seo'
6- import { GlobeAltIcon } from '@heroicons/react/outline'
7- import { Check } from 'lucide-react'
8- import { Badge , Button , Separator , buttonVariants , cn } from 'ui'
98import ReactMarkdown from 'react-markdown'
9+ import { Badge , Button , buttonVariants , cn , Separator } from 'ui'
10+ import { z } from 'zod'
1011import Styles from '~/styles/career.module.css'
1112
1213import Globe from '~/components/Globe'
1314import DefaultLayout from '~/components/Layouts/Default'
1415import SectionContainer from '~/components/Layouts/SectionContainer'
1516
16- import { groupJobsByTeam , filterGenericJob , JobItemProps , PLACEHOLDER_JOB_ID } from '~/lib/careers'
1717import career from '~/data/career.json'
18+ import { filterGenericJob , groupJobsByTeam , JobItemProps , PLACEHOLDER_JOB_ID } from '~/lib/careers'
19+
20+ const ContributorSchema = z . object ( {
21+ login : z . string ( ) ,
22+ avatar_url : z . string ( ) ,
23+ html_url : z . string ( ) ,
24+ } )
25+
26+ type Contributor = z . infer < typeof ContributorSchema >
1827
1928export const getServerSideProps : GetServerSideProps = ( async ( { res } ) => {
2029 // refresh every 5 minutes
2130 res . setHeader ( 'Cache-Control' , 'public, max-age=300, stale-while-revalidate=300' )
2231
2332 const job_res = await fetch ( 'https://api.ashbyhq.com/posting-api/job-board/supabase' )
24- const job_data = await job_res . json ( )
33+ const job_data = ( await job_res . json ( ) ) as { jobs : JobItemProps [ ] }
2534
26- const jobs = groupJobsByTeam ( job_data . jobs . filter ( ( job : JobItemProps ) => ! filterGenericJob ( job ) ) )
35+ const jobs = groupJobsByTeam ( job_data . jobs . filter ( ( job ) => ! filterGenericJob ( job ) ) )
2736 const placeholderJob = job_data . jobs . find ( filterGenericJob )
2837
29- const contributor_res = await fetch (
38+ const contributorResponse = await fetch (
3039 'https://api.github.com/repos/supabase/supabase/contributors?per_page=100'
3140 )
32- const contributor_arr = await contributor_res . json ( )
41+ let contributorArray : Contributor [ ] = [ ]
42+ try {
43+ const contributorResponseData = await contributorResponse . json ( )
44+ // if the response is not in the expected format, throw an error and return an empty array
45+ contributorArray = ContributorSchema . array ( ) . parse ( contributorResponseData )
46+ } catch { }
3347
34- const contributor_data = await contributor_arr . map (
35- ( contributor : { login : string ; avatar_url : string ; html_url : string } ) => {
36- return {
37- login : contributor . login ,
38- avatar_url : contributor . avatar_url ,
39- html_url : contributor . html_url ,
40- }
48+ const contributor_data = contributorArray . map ( ( contributor ) => {
49+ return {
50+ login : contributor . login ,
51+ avatar_url : contributor . avatar_url ,
52+ html_url : contributor . html_url ,
4153 }
42- )
54+ } )
4355
44- const contributors = await contributor_data . filter ( ( contributor : any ) =>
56+ const contributors = await contributor_data . filter ( ( contributor ) =>
4557 career . contributors . includes ( contributor . login )
4658 )
4759
@@ -74,11 +86,11 @@ export const getServerSideProps: GetServerSideProps = (async ({ res }) => {
7486
7587interface CareersPageProps {
7688 jobs : Record < string , JobItemProps [ ] >
77- placeholderJob : JobItemProps
89+ placeholderJob : JobItemProps | null
7890 contributors : { login : string ; avatar_url : string ; html_url : string } [ ]
7991}
8092
81- const CareerPage : NextPage < CareersPageProps > = ( { jobs, placeholderJob, contributors } ) => {
93+ const CareerPage = ( { jobs, placeholderJob, contributors } : CareersPageProps ) => {
8294 const { basePath } = useRouter ( )
8395
8496 const meta_title = 'Careers | Supabase'
@@ -118,7 +130,7 @@ const CareerPage: NextPage<CareersPageProps> = ({ jobs, placeholderJob, contribu
118130
119131 < SectionContainer className = "!pt-8" >
120132 < div className = "flex flex-wrap md:flex-nowrap -mt-6 md:mt-0 w-fit md:w-full mx-auto md:flex md:items-start justify-around lg:w-full lg:max-w-5xl" >
121- { career . company . map ( ( company : { number : string ; text : string } , i : number ) => {
133+ { career . company . map ( ( company , i ) => {
122134 return (
123135 < div
124136 key = { i }
@@ -284,18 +296,16 @@ const CareerPage: NextPage<CareersPageProps> = ({ jobs, placeholderJob, contribu
284296 our team effective:
285297 </ p >
286298 < div className = "grid pt-10 gap-8 grid-cols-2 md:grid-cols-3 lg:gap-16 lg:grid-cols-5" >
287- { career . humanPowered . map (
288- ( human : { icon : string ; title : string ; text : string } , i : number ) => {
289- return (
290- < div key = { i } className = "flex flex-col gap-3" >
291- < div >
292- < h3 className = "text-base" > { human . title } </ h3 >
293- < p className = "text-foreground-light text-xs lg:text-sm" > { human . text } </ p >
294- </ div >
299+ { career . humanPowered . map ( ( human , i ) => {
300+ return (
301+ < div key = { i } className = "flex flex-col gap-3" >
302+ < div >
303+ < h3 className = "text-base" > { human . title } </ h3 >
304+ < p className = "text-foreground-light text-xs lg:text-sm" > { human . text } </ p >
295305 </ div >
296- )
297- }
298- ) }
306+ </ div >
307+ )
308+ } ) }
299309 </ div >
300310 </ SectionContainer >
301311
@@ -312,7 +322,7 @@ const CareerPage: NextPage<CareersPageProps> = ({ jobs, placeholderJob, contribu
312322 </ p >
313323 </ div >
314324 < div className = "w-[1080px] h-[370px] mx-auto sm:mt-10 md:mt-16 lg:mt-28 2xl:mt-60" >
315- { contributors . map ( ( contributor : any , i : number ) => {
325+ { contributors . map ( ( contributor , i ) => {
316326 return (
317327 < div
318328 className = { `${
@@ -372,20 +382,16 @@ const CareerPage: NextPage<CareersPageProps> = ({ jobs, placeholderJob, contribu
372382 </ h2 >
373383 </ div >
374384 < div className = "mt-12 xl:mt-0 space-y-6 lg:space-y-0 sm:w-fit sm:mx-auto lg:grid lg:grid-cols-2 lg:gap-16" >
375- { career . benefits . map (
376- ( benefits : { icon : string ; title : string ; text : string } , i : number ) => {
377- return (
378- < div className = "h-full flex items-start space-x-6 w-full" key = { i } >
379- < div className = "h-fit text-sm lg:text-base" >
380- < h3 className = "text-sm" > { benefits . title } </ h3 >
381- < ReactMarkdown className = "prose pt-1 text-sm" >
382- { benefits . text }
383- </ ReactMarkdown >
384- </ div >
385+ { career . benefits . map ( ( benefits , i ) => {
386+ return (
387+ < div className = "h-full flex items-start space-x-6 w-full" key = { i } >
388+ < div className = "h-fit text-sm lg:text-base" >
389+ < h3 className = "text-sm" > { benefits . title } </ h3 >
390+ < ReactMarkdown className = "prose pt-1 text-sm" > { benefits . text } </ ReactMarkdown >
385391 </ div >
386- )
387- }
388- ) }
392+ </ div >
393+ )
394+ } ) }
389395 </ div >
390396 </ div >
391397 </ SectionContainer >
@@ -401,7 +407,7 @@ const CareerPage: NextPage<CareersPageProps> = ({ jobs, placeholderJob, contribu
401407 </ p >
402408 </ div >
403409 < div className = "mt-16 md:ml-36 lg:flex lg:items-start lg:w-fit lg:mx-auto" >
404- { career . hiring . map ( ( hiring : { title : string ; text : string } , i : number ) => {
410+ { career . hiring . map ( ( hiring , i ) => {
405411 return (
406412 < div
407413 key = { i + 1 }
@@ -444,9 +450,9 @@ const CareerPage: NextPage<CareersPageProps> = ({ jobs, placeholderJob, contribu
444450 < div key = { team } >
445451 < h3 className = "text-foreground-lighter text-sm" > { team } </ h3 >
446452 < div className = "mt-2 -space-y-px" >
447- { ( teamJobs as JobItemProps [ ] )
448- . filter ( ( job : any ) => ! filterGenericJob ( job ) )
449- . map ( ( job : JobItemProps ) => (
453+ { teamJobs
454+ . filter ( ( job ) => ! filterGenericJob ( job ) )
455+ . map ( ( job ) => (
450456 < JobItem job = { job } key = { job . id } />
451457 ) ) }
452458 </ div >
@@ -481,7 +487,7 @@ const CareerPage: NextPage<CareersPageProps> = ({ jobs, placeholderJob, contribu
481487 )
482488}
483489
484- const JobItem : React . FC < { job : JobItemProps } > = ( { job } ) => {
490+ const JobItem = ( { job } : { job : JobItemProps } ) => {
485491 const isPlaceholderJob = job . id === PLACEHOLDER_JOB_ID
486492
487493 return (
0 commit comments