11import React , { useEffect , useState } from "react" ;
22import Layout from "@theme/Layout" ;
3+ import { createClient } from "@sanity/client" ;
34
45interface Author {
56 name : string ;
6- url ?: string ;
7+ linkedinUrl ?: string ;
78}
89
910interface Resource {
@@ -14,10 +15,18 @@ interface Resource {
1415 category : string ;
1516 url : string ;
1617 summary ?: string ;
17- repo_org ?: string ;
18- repo_name ?: string ;
18+ repoOrg ?: string ;
19+ repoName ?: string ;
1920}
2021
22+ // Create Sanity client
23+ const client = createClient ( {
24+ projectId : "5f7a73bz" ,
25+ dataset : "production" ,
26+ useCdn : false , // Since the site is behind Cloudflare, we don't need Sanity CDN
27+ apiVersion : "2025-02-06" ,
28+ } ) ;
29+
2130function ResourcesPage ( ) {
2231 const [ resources , setResources ] = useState < Resource [ ] > ( [ ] ) ;
2332 const [ searchTerm , setSearchTerm ] = useState ( "" ) ;
@@ -41,8 +50,8 @@ function ResourcesPage() {
4150 ? resource . authors . map ( ( a ) => a . name ) . join ( " " )
4251 : "" ;
4352 const repoString =
44- resource . repo_org && resource . repo_name
45- ? `${ resource . repo_org } ${ resource . repo_name } `
53+ resource . repoOrg && resource . repoName
54+ ? `${ resource . repoOrg } ${ resource . repoName } `
4655 : "" ;
4756 const searchString =
4857 `${ resource . title } ${ resource . summary } ${ authorString } ${ repoString } ${ resource . type } ${ resource . category } ` . toLowerCase ( ) ;
@@ -58,24 +67,38 @@ function ResourcesPage() {
5867 } ) ;
5968
6069 useEffect ( ( ) => {
61- fetch ( "/resources.json" )
62- . then ( ( response ) => response . json ( ) )
63- . then ( ( data : Resource [ ] ) => {
64- const sortedData = data . sort (
65- ( a , b ) => new Date ( b . date ) . getTime ( ) - new Date ( a . date ) . getTime ( ) ,
70+ const fetchResources = async ( ) => {
71+ try {
72+ const data : Resource [ ] = await client . fetch ( `
73+ *[_type == "resource"] | order(date desc) {
74+ ...,
75+ "authors": authors[]->{ name, linkedinUrl },
76+ "category": category->title,
77+ "type": type->title
78+ }
79+ ` ) ;
80+
81+ setResources ( data ) ;
82+ const allCategories = [ ...new Set ( data . map ( ( r ) => r . category ) ) ] . filter (
83+ ( cat ) : cat is string => typeof cat === "string" ,
84+ ) ;
85+ const allTypes = [ ...new Set ( data . map ( ( r ) => r . type ) ) ] . filter (
86+ ( type ) : type is string => typeof type === "string" ,
6687 ) ;
67- setResources ( sortedData ) ;
68- const allCategories = [ ...new Set ( data . map ( ( r ) => r . category ) ) ] ;
69- const allTypes = [ ...new Set ( data . map ( ( r ) => r . type ) ) ] ;
7088 const allYears = [
7189 ...new Set (
7290 data . map ( ( r ) => new Date ( r . date ) . getFullYear ( ) . toString ( ) ) ,
7391 ) ,
74- ] ;
92+ ] . filter ( ( year ) : year is string => typeof year === "string" ) ;
7593 setCategories ( allCategories . sort ( ) ) ;
7694 setTypes ( allTypes . sort ( ) ) ;
7795 setYears ( allYears . sort ( ) . reverse ( ) ) ;
78- } ) ;
96+ } catch ( error ) {
97+ console . error ( "Error fetching resources:" , error ) ;
98+ }
99+ } ;
100+
101+ fetchResources ( ) ;
79102 } , [ ] ) ;
80103
81104 return (
@@ -195,22 +218,22 @@ function ResourcesPage() {
195218 |{ " " }
196219 < span className = "font-bold" >
197220 { resource . type === "Code sample" &&
198- resource . repo_org &&
199- resource . repo_name ? (
221+ resource . repoOrg &&
222+ resource . repoName ? (
200223 < a
201224 href = { resource . url }
202225 target = "_blank"
203226 rel = "noopener noreferrer"
204227 className = "hover:underline"
205228 >
206- { resource . repo_org } /{ resource . repo_name }
229+ { resource . repoOrg } /{ resource . repoName }
207230 </ a >
208231 ) : (
209232 resource . authors ?. map ( ( author , index ) => (
210233 < React . Fragment key = { author . name } >
211- { author . url ? (
234+ { author . linkedinUrl ? (
212235 < a
213- href = { author . url }
236+ href = { author . linkedinUrl }
214237 target = "_blank"
215238 rel = "noopener noreferrer"
216239 className = "hover:underline"
0 commit comments