@la-main-verte/shared-types 1.0.82 → 1.0.83

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@la-main-verte/shared-types",
3
- "version": "1.0.82",
3
+ "version": "1.0.83",
4
4
  "description": "Shared TypeScript interfaces for frontend of la-main-verte app",
5
5
  "main": "src/index.js",
6
6
  "types": "src/index.d.ts",
package/src/home.api.d.ts CHANGED
@@ -1,258 +1,276 @@
1
- import type { PlantI } from './plant'
2
- import type { SelectionI } from './selection'
3
- import type { TaskI } from './task'
4
-
5
- export namespace HOME {
6
- export type HeroCardMode = 'featuredSelection' | 'featuredPlant'
7
-
8
- export type SectionComponentType =
9
- | 'Header'
10
- | 'HeroCards'
11
- | 'PlantCarousel'
12
- | 'HeroCardsCarousel'
13
- | 'WideCardsCarousel'
14
- | 'Weather'
15
- | 'AdviceCarousel'
16
- | 'OnboardingCard'
17
- | 'UpcomingTasks'
18
-
19
- export type CarouselComponentType = Extract<
20
- SectionComponentType,
21
- 'PlantCarousel' | 'HeroCardsCarousel' | 'WideCardsCarousel'
22
- >
23
-
24
- export interface WeatherDayI {
25
- date: string
26
- minTempC: number
27
- maxTempC: number
28
- iconUrl: string | null
29
- condition?: string | null
30
- }
31
-
32
- export interface WeatherSectionI {
33
- componentType: 'Weather'
34
- title: string
35
- subtitle?: string
36
- locationName: string
37
- timezone: string
38
- days: WeatherDayI[]
39
- lastUpdatedAt: string
40
- dataSource: 'weatherapi'
41
- backgroundColor?: string
42
- }
43
-
44
- export interface HeaderSectionI {
45
- componentType: 'Header'
46
- title: string
47
- subtitle: string
48
- }
49
-
50
- export interface AdviceI {
51
- id?: string | number
52
- title: string
53
- markdownContent: string
54
- titleColor?: string
55
- backgroundColor?: string
56
- }
57
-
58
- export interface AdviceSectionI {
59
- componentType: 'AdviceCarousel'
60
- title?: string
61
- subtitle?: string
62
- advices: AdviceI[]
63
- }
64
-
65
- export interface WideCardAuthorI {
66
- name?: string | null
67
- imageURL?: string | null
68
- }
69
-
70
- export interface WideCardItemI {
71
- id?: string | number
72
- title?: string | null
73
- text: string
74
- badgeText?: string | null
75
- thumbnailImageURL: string
76
- author?: WideCardAuthorI | null
77
- link?: string | null
78
- metadata?: Record<string, unknown>
79
- }
80
-
81
- export interface WideCardsCarouselSectionI {
82
- componentType: 'WideCardsCarousel'
83
- title: string
84
- subtitle?: string
85
- cards: WideCardItemI[]
86
- }
87
-
88
- export interface HeroCardBlueprintI {
89
- mode: HeroCardMode
90
- title?: string | null
91
- description?: string | null
92
- backgroundColor?: string | null
93
- backgroundImageUrl?: string | null
94
- ctaLabel?: string | null
95
- ctaRoute?: string | null
96
- previewPlants?: PlantI[]
97
- selection?: SelectionI | null
98
- plant?: PlantI | null
99
- }
100
-
101
- export interface HeroCardsSectionI {
102
- componentType: 'HeroCards'
103
- title?: string | null
104
- subtitle?: string | null
105
- cards: HeroCardBlueprintI[]
106
- }
107
-
108
- export interface PlantCarouselSectionI {
109
- componentType: 'PlantCarousel'
110
- title: string
111
- subtitle?: string
112
- selection: SelectionI
113
- displayRanking?: boolean
114
- }
115
-
116
- export interface HeroCardsCarouselSectionI {
117
- componentType: 'HeroCardsCarousel'
118
- selections: SelectionI[]
119
- }
120
-
121
- export interface FamilyRecommendationI {
122
- family: string
123
- headline: string
124
- plants: PlantI[]
125
- }
126
-
127
- export interface FamilyExplorerSectionI {
128
- componentType: 'FamilyExplorer'
129
- title: string
130
- subtitle?: string
131
- families: FamilyRecommendationI[]
132
- }
133
-
134
- export interface OnboardingStepI {
135
- id: string
136
- title: string
137
- description: string
138
- isCompleted: boolean
139
- ctaLink: string
140
- }
141
-
142
- export interface OnboardingCardSectionI {
143
- componentType: 'OnboardingCard'
144
- title: string
145
- subtitle: string
146
- steps: OnboardingStepI[]
147
- completedStepsCount: number
148
- totalStepsCount: number
149
- }
150
-
151
- /** Minimal plant info for preview display (e.g. parent plant in grouped tasks) */
152
- export interface TaskPlantPreviewI {
153
- name: string
154
- slug: string
155
- imageURL?: string | null
156
- }
157
-
158
- /** Plant info within a family group — includes the task ID specific to this plant */
159
- export interface TaskFamilyPlantPreviewI extends TaskPlantPreviewI {
160
- taskId: number
161
- }
162
-
163
- /** Family group info when multiple plants share the same task */
164
- export interface TaskFamilyGroupI {
165
- familyName: string
166
- plantsCount: number
167
- plants: TaskFamilyPlantPreviewI[]
168
- }
169
-
170
- export interface UpcomingTaskI {
171
- task: TaskI
172
- plantName: string
173
- plantSlug: string
174
- plantImageURL?: string | null
175
- gardenName: string
176
- gardenCategory: string
177
- selectionSlug: string
178
- /** If this task is grouped by family */
179
- familyGroup?: TaskFamilyGroupI
180
- }
181
-
182
- export interface UpcomingTaskAdviceI {
183
- /** @deprecated Since 1.9.10, this field is always `''`. */
184
- content: string
185
- taskName: string
186
- plantName: string
187
- plantSlug: string
188
- plantImageURL?: string | null
189
- gardenName: string
190
- gardenCategory: string
191
- selectionSlug: string
192
- task: TaskI
193
- /** If this task is grouped by family */
194
- familyGroup?: TaskFamilyGroupI
195
- }
196
-
197
- export interface UpcomingTasksSectionI {
198
- componentType: 'UpcomingTasks'
199
- title: string
200
- subtitle?: string
201
- advices: UpcomingTaskAdviceI[]
202
- }
203
-
204
- /** Preview plant for WhenToSeedWhat section */
205
- export interface WhenToSeedWhatPlantPreviewI {
206
- id: number
207
- name: string
208
- family?: string | null
209
- slug: string
210
- imageURL?: string | null
211
- }
212
-
213
- /** A generic link card section with title, subtitle, URL, and optional preview images */
214
- export interface LinkCardSectionI {
215
- componentType: 'LinkCard'
216
- title: string
217
- subtitle?: string
218
- url: string
219
- previewPlants?: WhenToSeedWhatPlantPreviewI[]
220
- backgroundColor?: string
221
- /** Show a red badge indicator (replaces the plant preview stack when true) */
222
- showBadge?: boolean
223
- /** Optional badge count to display */
224
- badgeCount?: number
225
- }
226
-
227
- export type SectionI =
228
- | HeaderSectionI
229
- | HeroCardsSectionI
230
- | PlantCarouselSectionI
231
- | HeroCardsCarouselSectionI
232
- | WideCardsCarouselSectionI
233
- | WeatherSectionI
234
- | AdviceSectionI
235
- | OnboardingCardSectionI
236
- | UpcomingTasksSectionI
237
- | LinkCardSectionI
238
-
239
- export interface Response {
240
- sections: SectionI[]
241
- weather?: WeatherSectionI
242
- advice?: AdviceSectionI
243
- }
244
-
245
- export interface HeroCardItemI {
246
- id?: string | null
247
- mode: HeroCardMode
248
- title?: string | null
249
- description?: string | null
250
- backgroundColor?: string | null
251
- backgroundImageUrl?: string | null
252
- previewPlants?: PlantI[]
253
- ctaLabel?: string | null
254
- selection?: SelectionI | null
255
- plant?: PlantI | null
256
- ctaRoute?: string | null
257
- }
258
- }
1
+ import type { PlantI } from './plant'
2
+ import type { SelectionI } from './selection'
3
+ import type { TaskI } from './task'
4
+
5
+ export namespace HOME {
6
+ export type HeroCardMode = 'featuredSelection' | 'featuredPlant'
7
+
8
+ export type SectionComponentType =
9
+ | 'Header'
10
+ | 'HeroCards'
11
+ | 'PlantCarousel'
12
+ | 'HeroCardsCarousel'
13
+ | 'WideCardsCarousel'
14
+ | 'Weather'
15
+ | 'AdviceCarousel'
16
+ | 'OnboardingCard'
17
+ | 'UpcomingTasks'
18
+
19
+ export type CarouselComponentType = Extract<
20
+ SectionComponentType,
21
+ 'PlantCarousel' | 'HeroCardsCarousel' | 'WideCardsCarousel'
22
+ >
23
+
24
+ export interface WeatherDayI {
25
+ date: string
26
+ minTempC: number
27
+ maxTempC: number
28
+ iconUrl: string | null
29
+ condition?: string | null
30
+ }
31
+
32
+ export interface WeatherSectionI {
33
+ componentType: 'Weather'
34
+ title: string
35
+ subtitle?: string
36
+ locationName: string
37
+ timezone: string
38
+ days: WeatherDayI[]
39
+ lastUpdatedAt: string
40
+ dataSource: 'weatherapi'
41
+ backgroundColor?: string
42
+ }
43
+
44
+ export interface HeaderSectionI {
45
+ componentType: 'Header'
46
+ title: string
47
+ subtitle: string
48
+ }
49
+
50
+ export interface AdviceI {
51
+ id?: string | number
52
+ title: string
53
+ markdownContent: string
54
+ titleColor?: string
55
+ backgroundColor?: string
56
+ }
57
+
58
+ export interface AdviceSectionI {
59
+ componentType: 'AdviceCarousel'
60
+ title?: string
61
+ subtitle?: string
62
+ advices: AdviceI[]
63
+ }
64
+
65
+ export interface WideCardAuthorI {
66
+ name?: string | null
67
+ imageURL?: string | null
68
+ }
69
+
70
+ export interface WideCardItemI {
71
+ id?: string | number
72
+ title?: string | null
73
+ text: string
74
+ badgeText?: string | null
75
+ thumbnailImageURL: string
76
+ author?: WideCardAuthorI | null
77
+ link?: string | null
78
+ metadata?: Record<string, unknown>
79
+ }
80
+
81
+ export interface WideCardsCarouselSectionI {
82
+ componentType: 'WideCardsCarousel'
83
+ title: string
84
+ subtitle?: string
85
+ cards: WideCardItemI[]
86
+ }
87
+
88
+ export interface HeroCardBlueprintI {
89
+ mode: HeroCardMode
90
+ title?: string | null
91
+ description?: string | null
92
+ backgroundColor?: string | null
93
+ backgroundImageUrl?: string | null
94
+ ctaLabel?: string | null
95
+ ctaRoute?: string | null
96
+ previewPlants?: PlantI[]
97
+ selection?: SelectionI | null
98
+ plant?: PlantI | null
99
+ }
100
+
101
+ export interface HeroCardsSectionI {
102
+ componentType: 'HeroCards'
103
+ title?: string | null
104
+ subtitle?: string | null
105
+ cards: HeroCardBlueprintI[]
106
+ }
107
+
108
+ export interface PlantCarouselSectionI {
109
+ componentType: 'PlantCarousel'
110
+ title: string
111
+ subtitle?: string
112
+ selection: SelectionI
113
+ displayRanking?: boolean
114
+ }
115
+
116
+ export interface HeroCardsCarouselSectionI {
117
+ componentType: 'HeroCardsCarousel'
118
+ selections: SelectionI[]
119
+ }
120
+
121
+ export interface FamilyRecommendationI {
122
+ family: string
123
+ headline: string
124
+ plants: PlantI[]
125
+ }
126
+
127
+ export interface FamilyExplorerSectionI {
128
+ componentType: 'FamilyExplorer'
129
+ title: string
130
+ subtitle?: string
131
+ families: FamilyRecommendationI[]
132
+ }
133
+
134
+ export interface OnboardingStepI {
135
+ id: string
136
+ title: string
137
+ description: string
138
+ isCompleted: boolean
139
+ ctaLink: string
140
+ }
141
+
142
+ export interface OnboardingCardSectionI {
143
+ componentType: 'OnboardingCard'
144
+ title: string
145
+ subtitle: string
146
+ steps: OnboardingStepI[]
147
+ completedStepsCount: number
148
+ totalStepsCount: number
149
+ }
150
+
151
+ /** Minimal plant info for preview display (e.g. parent plant in grouped tasks) */
152
+ export interface TaskPlantPreviewI {
153
+ name: string
154
+ slug: string
155
+ imageURL?: string | null
156
+ }
157
+
158
+ /** Plant info within a family group — includes the task ID specific to this plant */
159
+ export interface TaskFamilyPlantPreviewI extends TaskPlantPreviewI {
160
+ taskId: number
161
+ }
162
+
163
+ /** Family group info when multiple plants share the same task */
164
+ export interface TaskFamilyGroupI {
165
+ familyName: string
166
+ plantsCount: number
167
+ plants: TaskFamilyPlantPreviewI[]
168
+ }
169
+
170
+ export interface UpcomingTaskI {
171
+ task: TaskI
172
+ /** PlantSelection id used by task list views to group tasks per planted item. */
173
+ plantSelectionId?: number
174
+ plantName: string
175
+ plantSlug: string
176
+ plantImageURL?: string | null
177
+ gardenName: string
178
+ gardenCategory: string
179
+ selectionSlug: string
180
+ /** If this task is grouped by family */
181
+ familyGroup?: TaskFamilyGroupI
182
+ }
183
+
184
+ export type TaskListView = 'current' | 'completed' | 'earlier'
185
+
186
+ export interface TaskListTabI {
187
+ key: TaskListView
188
+ label: string
189
+ }
190
+
191
+ export interface TaskListResponseI {
192
+ view: TaskListView
193
+ title: string
194
+ subtitle: string
195
+ emptyListMessage: string
196
+ tabs: TaskListTabI[]
197
+ tasks: UpcomingTaskI[]
198
+ }
199
+
200
+ export interface UpcomingTaskAdviceI {
201
+ /** @deprecated Since 1.9.10, this field is always `''`. */
202
+ content: string
203
+ taskName: string
204
+ plantName: string
205
+ plantSlug: string
206
+ plantImageURL?: string | null
207
+ gardenName: string
208
+ gardenCategory: string
209
+ selectionSlug: string
210
+ task: TaskI
211
+ /** If this task is grouped by family */
212
+ familyGroup?: TaskFamilyGroupI
213
+ }
214
+
215
+ export interface UpcomingTasksSectionI {
216
+ componentType: 'UpcomingTasks'
217
+ title: string
218
+ subtitle?: string
219
+ advices: UpcomingTaskAdviceI[]
220
+ }
221
+
222
+ /** Preview plant for WhenToSeedWhat section */
223
+ export interface WhenToSeedWhatPlantPreviewI {
224
+ id: number
225
+ name: string
226
+ family?: string | null
227
+ slug: string
228
+ imageURL?: string | null
229
+ }
230
+
231
+ /** A generic link card section with title, subtitle, URL, and optional preview images */
232
+ export interface LinkCardSectionI {
233
+ componentType: 'LinkCard'
234
+ title: string
235
+ subtitle?: string
236
+ url: string
237
+ previewPlants?: WhenToSeedWhatPlantPreviewI[]
238
+ backgroundColor?: string
239
+ /** Show a red badge indicator (replaces the plant preview stack when true) */
240
+ showBadge?: boolean
241
+ /** Optional badge count to display */
242
+ badgeCount?: number
243
+ }
244
+
245
+ export type SectionI =
246
+ | HeaderSectionI
247
+ | HeroCardsSectionI
248
+ | PlantCarouselSectionI
249
+ | HeroCardsCarouselSectionI
250
+ | WideCardsCarouselSectionI
251
+ | WeatherSectionI
252
+ | AdviceSectionI
253
+ | OnboardingCardSectionI
254
+ | UpcomingTasksSectionI
255
+ | LinkCardSectionI
256
+
257
+ export interface Response {
258
+ sections: SectionI[]
259
+ weather?: WeatherSectionI
260
+ advice?: AdviceSectionI
261
+ }
262
+
263
+ export interface HeroCardItemI {
264
+ id?: string | null
265
+ mode: HeroCardMode
266
+ title?: string | null
267
+ description?: string | null
268
+ backgroundColor?: string | null
269
+ backgroundImageUrl?: string | null
270
+ previewPlants?: PlantI[]
271
+ ctaLabel?: string | null
272
+ selection?: SelectionI | null
273
+ plant?: PlantI | null
274
+ ctaRoute?: string | null
275
+ }
276
+ }
package/src/index.ts CHANGED
@@ -1,34 +1,34 @@
1
- export * from './member'
2
- export * from './selection'
3
- export * from './plantSelection'
4
- export * from './plant'
5
- export * from './task'
6
- export * from './calendarView'
7
- export * from './apiError'
8
- export * from './gardenMap'
9
- export * from './gardenOverview'
10
- export * from './alert'
11
- export * from './image'
12
- export * from './note'
13
- export * from './taggedItem'
14
- export * from './fertilizer'
15
- export * from './utmParams'
16
- export * from './plantFilters'
17
- export * from './taxonFamily'
18
- export * from './rotationGroup'
19
- import * as PlantsAPI from './plants.api'
20
- import * as UsersAPI from './users.api'
21
- import * as SessionsAPI from './sessions.api'
22
- import * as HomeAPI from './home.api'
23
- import * as PagesAPI from './pages.api'
24
- import * as PaymentsAPI from './payments.api'
25
-
26
- // Allow access to the API namespaces without conflicts
27
- export namespace API {
28
- export import PLANTS = PlantsAPI
29
- export import USERS = UsersAPI
30
- export import SESSIONS = SessionsAPI
31
- export import HOME = HomeAPI
32
- export import PAGES = PagesAPI
33
- export import PAYMENTS = PaymentsAPI
34
- }
1
+ export * from './member'
2
+ export * from './selection'
3
+ export * from './plantSelection'
4
+ export * from './plant'
5
+ export * from './task'
6
+ export * from './calendarView'
7
+ export * from './apiError'
8
+ export * from './gardenMap'
9
+ export * from './gardenOverview'
10
+ export * from './alert'
11
+ export * from './image'
12
+ export * from './note'
13
+ export * from './taggedItem'
14
+ export * from './fertilizer'
15
+ export * from './utmParams'
16
+ export * from './plantFilters'
17
+ export * from './taxonFamily'
18
+ export * from './rotationGroup'
19
+ import * as PlantsAPI from './plants.api'
20
+ import * as UsersAPI from './users.api'
21
+ import * as SessionsAPI from './sessions.api'
22
+ import * as HomeAPI from './home.api'
23
+ import * as PagesAPI from './pages.api'
24
+ import * as PaymentsAPI from './payments.api'
25
+
26
+ // Allow access to the API namespaces without conflicts
27
+ export namespace API {
28
+ export import PLANTS = PlantsAPI
29
+ export import USERS = UsersAPI
30
+ export import SESSIONS = SessionsAPI
31
+ export import HOME = HomeAPI
32
+ export import PAGES = PagesAPI
33
+ export import PAYMENTS = PaymentsAPI
34
+ }
package/src/plant.d.ts CHANGED
@@ -1,189 +1,189 @@
1
- import type { TaxonFamilyI } from './taxonFamily'
2
- import type { SeedingInfoI } from './pages.api'
3
- import type { PlantFilterI } from './plantFilters'
4
- import type { RotationGroup } from './rotationGroup'
5
- /**
6
- * Range filter value for min/max filters
7
- */
8
- export interface RangeFilterValueI {
9
- min: number
10
- max: number
11
- }
12
-
13
- /**
14
- * Plant filter value types
15
- * Represents the possible values for a single filter
16
- */
17
- export type PlantFilterValueI = string | string[] | number | boolean | RangeFilterValueI
18
-
19
- /**
20
- * Plant attributes for filtering
21
- * Used in JSONB field and as query parameters
22
- * Supports multiple value types for different filter types
23
- */
24
- export type PlantAttributesI = Record<string, PlantFilterValueI>
25
-
26
- export interface PlantI {
27
- id: number
28
- name: string
29
- slug: string
30
- description: string
31
- descriptionSource?: string
32
- female: boolean
33
- family?: string | null
34
- taxonFamilyId?: number | null
35
- spaceBetweenSeedMin: number
36
- spaceBetweenSeedMax: number
37
- spaceBetweenAlleyMin: number
38
- spaceBetweenAlleyMax: number
39
- weeksInTransplant: number
40
- weeksDuringWhichYouCanSeedOutdoor: number
41
- weeksToMaturity: number
42
- daysToMaturity: number | null
43
- weeksToWaitAfterFreezingDate: number
44
- weeksToHarvest: number
45
- indoorSeeding: boolean
46
- outdoorSeeding: boolean
47
- azoteNeedsKgPerHa: number
48
- hibernate: boolean
49
- germinationTemperature: number | null
50
- minGerminationTemperature: number | null
51
- germinationNumberOfDays: string | null
52
- germinationSeedDepth: string | null
53
- cultivationInfo: string | null
54
- parentId: number | null
55
- memberId?: number
56
- memberFirstName?: string | null
57
- shared: boolean
58
- hexColor: string | null
59
- sunRequirements: 'partialShade' | 'fullSun' | 'fullShade' | null
60
- isHardy: boolean | null
61
- quantityForFiveInJardinVivrier?: number | null
62
- imageURL: string
63
- /**
64
- * Filename of the plant's 3D mesh asset stored on S3.
65
- * - Ideally a `.webp` file (e.g. `ail.webp`).
66
- * - Stored in S3 under the `images/meshes/` folder.
67
- * - By default named after the `Plant.slug` (e.g. `ail.webp` for the garlic plant).
68
- * - Only the filename is persisted; the public URL is exposed through the
69
- * virtual `meshURL` field.
70
- */
71
- meshFilename: string | null
72
- /**
73
- * Public ImageKit URL to the plant's 3D mesh asset.
74
- * Virtual field computed from `meshFilename`. The underlying file is
75
- * stored on S3 at `images/meshes/{meshFilename}` and rewritten to
76
- * ImageKit for CDN delivery and transformations.
77
- *
78
- * Falls back to `imageURL` when `meshFilename` is not set.
79
- *
80
- * Example: `https://ik.imagekit.io/lamainverte/meshes/ail.webp`
81
- */
82
- meshURL: string
83
- totalWeeksToMaturity: number
84
- hasNoInformation: boolean
85
- createdAt: Date
86
- updatedAt: Date
87
- translatedSunRequirements: 'Plein soleil' | 'Mi-ombre' | 'Ombre' | null
88
- parent?: PlantI
89
- children?: PlantI[]
90
- PlantInventories?: PlantInventoryI[]
91
- taggedItems?: TaggedItemI[]
92
- /**
93
- * List of selections that the plant is in.
94
- * --------------------------------------
95
- * Tends to be used for featured selections
96
- */
97
- Selections?: SelectionI[]
98
- tasks?: TaskI[]
99
- Images?: ImageI[]
100
- Member?: Partial<MemberI>
101
- notes?: NoteI[]
102
- /**
103
- * Nitrogen-derived rotation group enum (virtual field on the Plant model).
104
- * Source of truth for rotation classification — derived from
105
- * `azoteNeedsKgPerHa` plus the regenerative override on `taxonFamily`.
106
- */
107
- rotationGroup?: RotationGroup | null
108
- /**
109
- * French label of `rotationGroup`, ready for display.
110
- */
111
- translatedRotationGroup?: string | null
112
- taxonFamily?: TaxonFamilyI
113
- seedingInfo: SeedingInfoI
114
- /**
115
- * Contextual search text for recommended plants
116
- * Provides additional context when suggesting plants for specific garden zones
117
- */
118
- contextualSearchText?: string
119
- }
120
-
121
- interface PlantInventoryI {
122
- id: number
123
- plantId: number
124
- supplierName: string
125
- plantName: string
126
- supplierURL: string
127
- imageLocation: string
128
- description: string
129
- inStock: boolean
130
- }
131
-
132
- export type AvailableGrowingConditionsI = Record<string, string[]>
133
-
134
- /**
135
- * For each attribute filter key (e.g. "fruit.color"), the list of values that
136
- * still yield at least one match under the current search + active filters.
137
- * Consumed by the frontend to mark filter tags as "unavailable".
138
- */
139
- export type AvailableAttributesI = Record<string, string[]>
140
-
141
- /**
142
- * Which filter surface the frontend should render for the current search.
143
- * - `specific`: family-specific filters (e.g. tomate attributes)
144
- * - `general`: global growing-conditions filters
145
- *
146
- * Mutually exclusive by design — the two sets never appear together.
147
- */
148
- export type PlantFiltersModeI = 'specific' | 'general'
149
-
150
- /**
151
- * Backend-driven description of the filter UI for a given search response.
152
- * The frontend is a dumb renderer: it shows the filters listed here with the
153
- * given mode and marks tags whose value is not in `availability` as unavailable.
154
- */
155
- export interface PlantFiltersUII {
156
- mode: PlantFiltersModeI
157
- filters: PlantFilterI[]
158
- availability: Record<string, string[]>
159
- }
160
-
161
- export interface GrowingConditionsConfigI {
162
- filters: PlantFilterI[]
163
- }
164
-
165
- export interface GrowingConditionsFiltersI {
166
- sunRequirements?: 'partialShade' | 'fullShade'
167
- rotationGroup?: 'regenerative' | 'demanding' | 'moderately_demanding' | 'less_demanding'
168
- }
169
-
170
- export interface PlantSearchResultI {
171
- plants: PlantModelI[]
172
- selections: SelectionModelI[]
173
- total?: number
174
- familyName?: string
175
- filtersUI?: PlantFiltersUII
176
- }
177
-
178
- /**
179
- * Response shape for `GET /selections/:slug/gardenZones/:id/rotation-suggestions`.
180
- * - `advice`: short user-facing sentence explaining the recommendation
181
- * - `Plants`: parent plants matching the recommended rotation group, with
182
- * the avoided taxon families excluded. Empty when the zone has no usable
183
- * history yet.
184
- */
185
- export interface PlantRotationSuggestionsI {
186
- targetYear: number
187
- advice: string
188
- Plants: PlantI[]
189
- }
1
+ import type { TaxonFamilyI } from './taxonFamily'
2
+ import type { SeedingInfoI } from './pages.api'
3
+ import type { PlantFilterI } from './plantFilters'
4
+ import type { RotationGroup } from './rotationGroup'
5
+ /**
6
+ * Range filter value for min/max filters
7
+ */
8
+ export interface RangeFilterValueI {
9
+ min: number
10
+ max: number
11
+ }
12
+
13
+ /**
14
+ * Plant filter value types
15
+ * Represents the possible values for a single filter
16
+ */
17
+ export type PlantFilterValueI = string | string[] | number | boolean | RangeFilterValueI
18
+
19
+ /**
20
+ * Plant attributes for filtering
21
+ * Used in JSONB field and as query parameters
22
+ * Supports multiple value types for different filter types
23
+ */
24
+ export type PlantAttributesI = Record<string, PlantFilterValueI>
25
+
26
+ export interface PlantI {
27
+ id: number
28
+ name: string
29
+ slug: string
30
+ description: string
31
+ descriptionSource?: string
32
+ female: boolean
33
+ family?: string | null
34
+ taxonFamilyId?: number | null
35
+ spaceBetweenSeedMin: number
36
+ spaceBetweenSeedMax: number
37
+ spaceBetweenAlleyMin: number
38
+ spaceBetweenAlleyMax: number
39
+ weeksInTransplant: number
40
+ weeksDuringWhichYouCanSeedOutdoor: number
41
+ weeksToMaturity: number
42
+ daysToMaturity: number | null
43
+ weeksToWaitAfterFreezingDate: number
44
+ weeksToHarvest: number
45
+ indoorSeeding: boolean
46
+ outdoorSeeding: boolean
47
+ azoteNeedsKgPerHa: number
48
+ hibernate: boolean
49
+ germinationTemperature: number | null
50
+ minGerminationTemperature: number | null
51
+ germinationNumberOfDays: string | null
52
+ germinationSeedDepth: string | null
53
+ cultivationInfo: string | null
54
+ parentId: number | null
55
+ memberId?: number
56
+ memberFirstName?: string | null
57
+ shared: boolean
58
+ hexColor: string | null
59
+ sunRequirements: 'partialShade' | 'fullSun' | 'fullShade' | null
60
+ isHardy: boolean | null
61
+ quantityForFiveInJardinVivrier?: number | null
62
+ imageURL: string
63
+ /**
64
+ * Filename of the plant's 3D mesh asset stored on S3.
65
+ * - Ideally a `.webp` file (e.g. `ail.webp`).
66
+ * - Stored in S3 under the `images/meshes/` folder.
67
+ * - By default named after the `Plant.slug` (e.g. `ail.webp` for the garlic plant).
68
+ * - Only the filename is persisted; the public URL is exposed through the
69
+ * virtual `meshURL` field.
70
+ */
71
+ meshFilename: string | null
72
+ /**
73
+ * Public ImageKit URL to the plant's 3D mesh asset.
74
+ * Virtual field computed from `meshFilename`. The underlying file is
75
+ * stored on S3 at `images/meshes/{meshFilename}` and rewritten to
76
+ * ImageKit for CDN delivery and transformations.
77
+ *
78
+ * Falls back to `imageURL` when `meshFilename` is not set.
79
+ *
80
+ * Example: `https://ik.imagekit.io/lamainverte/meshes/ail.webp`
81
+ */
82
+ meshURL: string
83
+ totalWeeksToMaturity: number
84
+ hasNoInformation: boolean
85
+ createdAt: Date
86
+ updatedAt: Date
87
+ translatedSunRequirements: 'Plein soleil' | 'Mi-ombre' | 'Ombre' | null
88
+ parent?: PlantI
89
+ children?: PlantI[]
90
+ PlantInventories?: PlantInventoryI[]
91
+ taggedItems?: TaggedItemI[]
92
+ /**
93
+ * List of selections that the plant is in.
94
+ * --------------------------------------
95
+ * Tends to be used for featured selections
96
+ */
97
+ Selections?: SelectionI[]
98
+ tasks?: TaskI[]
99
+ Images?: ImageI[]
100
+ Member?: Partial<MemberI>
101
+ notes?: NoteI[]
102
+ /**
103
+ * Nitrogen-derived rotation group enum (virtual field on the Plant model).
104
+ * Source of truth for rotation classification — derived from
105
+ * `azoteNeedsKgPerHa` plus the regenerative override on `taxonFamily`.
106
+ */
107
+ rotationGroup?: RotationGroup | null
108
+ /**
109
+ * French label of `rotationGroup`, ready for display.
110
+ */
111
+ translatedRotationGroup?: string | null
112
+ taxonFamily?: TaxonFamilyI
113
+ seedingInfo: SeedingInfoI
114
+ /**
115
+ * Contextual search text for recommended plants
116
+ * Provides additional context when suggesting plants for specific garden zones
117
+ */
118
+ contextualSearchText?: string
119
+ }
120
+
121
+ interface PlantInventoryI {
122
+ id: number
123
+ plantId: number
124
+ supplierName: string
125
+ plantName: string
126
+ supplierURL: string
127
+ imageLocation: string
128
+ description: string
129
+ inStock: boolean
130
+ }
131
+
132
+ export type AvailableGrowingConditionsI = Record<string, string[]>
133
+
134
+ /**
135
+ * For each attribute filter key (e.g. "fruit.color"), the list of values that
136
+ * still yield at least one match under the current search + active filters.
137
+ * Consumed by the frontend to mark filter tags as "unavailable".
138
+ */
139
+ export type AvailableAttributesI = Record<string, string[]>
140
+
141
+ /**
142
+ * Which filter surface the frontend should render for the current search.
143
+ * - `specific`: family-specific filters (e.g. tomate attributes)
144
+ * - `general`: global growing-conditions filters
145
+ *
146
+ * Mutually exclusive by design — the two sets never appear together.
147
+ */
148
+ export type PlantFiltersModeI = 'specific' | 'general'
149
+
150
+ /**
151
+ * Backend-driven description of the filter UI for a given search response.
152
+ * The frontend is a dumb renderer: it shows the filters listed here with the
153
+ * given mode and marks tags whose value is not in `availability` as unavailable.
154
+ */
155
+ export interface PlantFiltersUII {
156
+ mode: PlantFiltersModeI
157
+ filters: PlantFilterI[]
158
+ availability: Record<string, string[]>
159
+ }
160
+
161
+ export interface GrowingConditionsConfigI {
162
+ filters: PlantFilterI[]
163
+ }
164
+
165
+ export interface GrowingConditionsFiltersI {
166
+ sunRequirements?: 'partialShade' | 'fullShade'
167
+ rotationGroup?: 'regenerative' | 'demanding' | 'moderately_demanding' | 'less_demanding'
168
+ }
169
+
170
+ export interface PlantSearchResultI {
171
+ plants: PlantModelI[]
172
+ selections: SelectionModelI[]
173
+ total?: number
174
+ familyName?: string
175
+ filtersUI?: PlantFiltersUII
176
+ }
177
+
178
+ /**
179
+ * Response shape for `GET /selections/:slug/gardenZones/:id/rotation-suggestions`.
180
+ * - `advice`: short user-facing sentence explaining the recommendation
181
+ * - `Plants`: parent plants matching the recommended rotation group, with
182
+ * the avoided taxon families excluded. Empty when the zone has no usable
183
+ * history yet.
184
+ */
185
+ export interface PlantRotationSuggestionsI {
186
+ targetYear: number
187
+ advice: string
188
+ Plants: PlantI[]
189
+ }
@@ -5,7 +5,6 @@ export interface PlantSelectionI {
5
5
  id: number
6
6
  plantId: number
7
7
  selectionId: number
8
- seedQuantity: number
9
8
  createdAt: Date
10
9
  updatedAt: Date
11
10
  Plant: PlantI
@@ -1,15 +1,15 @@
1
- import type { RotationGroup } from './rotationGroup'
2
-
3
- export interface TaxonFamilyI {
4
- id: number
5
- slug: string
6
- translation_key: string
7
- name: string
8
- latin_name: string | null
9
- kingdom: string
10
- description: string | null
11
- rotation_group: RotationGroup | null
12
- translated_rotation_group: string | null
13
- createdAt?: Date
14
- updatedAt?: Date
15
- }
1
+ import type { RotationGroup } from './rotationGroup'
2
+
3
+ export interface TaxonFamilyI {
4
+ id: number
5
+ slug: string
6
+ translation_key: string
7
+ name: string
8
+ latin_name: string | null
9
+ kingdom: string
10
+ description: string | null
11
+ rotation_group: RotationGroup | null
12
+ translated_rotation_group: string | null
13
+ createdAt?: Date
14
+ updatedAt?: Date
15
+ }