1
- import { escapeRegExp , filterListWithInitialMatchesFirst } from '@lib/util' ;
2
- import type { Category } from '@prisma/client' ;
1
+ import { escapeRegExp , filterListWithInitialMatchesFirst } from "@lib/util" ;
2
+ import type { Category } from "@prisma/client" ;
3
+ import { actions } from "astro:actions" ;
3
4
import {
4
5
type Accessor ,
5
6
type Component ,
@@ -12,56 +13,47 @@ import {
12
13
type Setter ,
13
14
Suspense ,
14
15
} from "solid-js" ;
15
- import { OneRecipe , type RecipeTitleWithLinkFields } from './OneRecipe' ;
16
- import { QueryDrivenTextField } from './QueryDrivenTextField' ;
17
-
18
- async function fetchRecipesForCategory ( categoryId : number , username : string | undefined ) {
19
- const searchParams = new URLSearchParams ( ) ;
20
- searchParams . set ( "id" , `${ categoryId } ` ) ;
21
- if ( username ) {
22
- searchParams . set ( "user" , username ) ;
23
- }
24
- let response = await fetch ( `/api/recipes-in-category?${ searchParams . toString ( ) } ` ) ;
25
- let recipes = await response . json ( ) as {
26
- name : string ;
27
- slug : string ;
28
- author : {
29
- username : string ;
30
- } ;
31
- } [ ] ;
32
- return recipes ;
33
- }
16
+ import { OneRecipe , type RecipeTitleWithLinkFields } from "./OneRecipe" ;
17
+ import { QueryDrivenTextField } from "./QueryDrivenTextField" ;
34
18
35
19
export const CategoryList : Component < {
36
20
categories : Category [ ] ;
37
- username ?: string ;
38
21
initialQuery : string ;
39
- } > = props => {
22
+ } > = ( props ) => {
40
23
// Keeping the search filter updated:
41
- const [ filter , setFilter ] = createSignal ( new URLSearchParams ( props . initialQuery ) . get ( "filter" ) ?? "" ) ;
24
+ const [ filter , setFilter ] = createSignal (
25
+ new URLSearchParams ( props . initialQuery ) . get ( "filter" ) ?? ""
26
+ ) ;
42
27
43
28
// Search for categories:
44
29
45
- const filterRE = createMemo ( ( ) => new RegExp ( escapeRegExp ( filter ( ) ) , 'i' ) ) ;
30
+ const filterRE = createMemo ( ( ) => new RegExp ( escapeRegExp ( filter ( ) ) , "i" ) ) ;
46
31
47
32
type PendingRecipeList = {
48
33
needRecipes : Accessor < boolean > ;
49
34
setNeedRecipes : Setter < boolean > ;
50
35
recipes : Resource < RecipeTitleWithLinkFields [ ] > ;
51
- }
36
+ } ;
52
37
53
38
const recipesByCategory = createMemo ( ( ) => {
54
- const username = props . username ;
55
- return new Map < number , PendingRecipeList > ( props . categories . map ( category => {
56
- const [ needRecipes , setNeedRecipes ] = createSignal ( false ) ;
57
- const [ recipes ] = createResource ( needRecipes , ( ) => fetchRecipesForCategory ( category . id , username ) ) ;
58
- return [ category . id , { needRecipes, setNeedRecipes, recipes } ] ;
59
- } ) ) ;
39
+ return new Map < number , PendingRecipeList > (
40
+ props . categories . map ( ( category ) => {
41
+ const [ needRecipes , setNeedRecipes ] = createSignal ( false ) ;
42
+ const [ recipes ] = createResource ( needRecipes , ( ) =>
43
+ actions . recipesInCategory . orThrow ( { categoryIds : [ category . id ] } )
44
+ ) ;
45
+ return [ category . id , { needRecipes, setNeedRecipes, recipes } ] ;
46
+ } )
47
+ ) ;
60
48
} ) ;
61
49
62
-
63
50
const filteredCategories = createMemo ( ( ) =>
64
- filterListWithInitialMatchesFirst ( props . categories , filterRE ( ) , c => c . name ) ) ;
51
+ filterListWithInitialMatchesFirst (
52
+ props . categories ,
53
+ filterRE ( ) ,
54
+ ( c ) => c . name
55
+ )
56
+ ) ;
65
57
66
58
function onToggleCategory ( categoryId : number ) {
67
59
recipesByCategory ( ) . get ( categoryId ) ?. setNeedRecipes ( true ) ;
@@ -75,27 +67,44 @@ export const CategoryList: Component<{
75
67
}
76
68
} ) ;
77
69
78
- return < >
79
- < QueryDrivenTextField queryParam = 'filter' value = { filter ( ) } onInput = { setFilter } > Filter</ QueryDrivenTextField >
80
- < section id = "categories" >
81
- < ul class = "details" >
82
- < For each = { filteredCategories ( ) } > { category =>
83
- < li >
84
- < details
85
- open = { filteredCategories ( ) . length === 1 }
86
- onToggle = { [ onToggleCategory , category . id ] } >
87
- < summary > { category . name } </ summary >
88
- < Suspense fallback = { < p > Loading...</ p > } >
89
- < ul >
90
- < For each = { recipesByCategory ( ) . get ( category . id ) ?. recipes ( ) } > { recipe =>
91
- < li > < OneRecipe recipe = { recipe } /> </ li >
92
- } </ For >
93
- </ ul >
94
- </ Suspense >
95
- </ details >
96
- </ li >
97
- } </ For >
98
- </ ul >
99
- </ section >
100
- </ > ;
101
- }
70
+ return (
71
+ < >
72
+ < QueryDrivenTextField
73
+ queryParam = "filter"
74
+ value = { filter ( ) }
75
+ onInput = { setFilter }
76
+ >
77
+ Filter
78
+ </ QueryDrivenTextField >
79
+ < section id = "categories" >
80
+ < ul class = "details" >
81
+ < For each = { filteredCategories ( ) } >
82
+ { ( category ) => (
83
+ < li >
84
+ < details
85
+ open = { filteredCategories ( ) . length === 1 }
86
+ onToggle = { [ onToggleCategory , category . id ] }
87
+ >
88
+ < summary > { category . name } </ summary >
89
+ < Suspense fallback = { < p > Loading...</ p > } >
90
+ < ul >
91
+ < For
92
+ each = { recipesByCategory ( ) . get ( category . id ) ?. recipes ( ) }
93
+ >
94
+ { ( recipe ) => (
95
+ < li >
96
+ < OneRecipe recipe = { recipe } />
97
+ </ li >
98
+ ) }
99
+ </ For >
100
+ </ ul >
101
+ </ Suspense >
102
+ </ details >
103
+ </ li >
104
+ ) }
105
+ </ For >
106
+ </ ul >
107
+ </ section >
108
+ </ >
109
+ ) ;
110
+ } ;
0 commit comments