@la-main-verte/shared-types 1.0.73 → 1.0.76

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.73",
3
+ "version": "1.0.76",
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/apiError.d.ts CHANGED
@@ -1,28 +1,49 @@
1
- export interface ApiErrorI {
2
- /**
3
- * Literally describe what the server error is, ideally in the language of the user
4
- */
5
- error_message?: string
6
- /**
7
- * A string code to identify the error
8
- */
9
- error_type?:
1
+ /**
2
+ * Standard API Response Types
3
+ * ------------------------------------------------------------------------------------------------
4
+ * These types define the standard shapes for all API responses.
5
+ * The frontend uses these to display toast notifications:
6
+ * - Error responses: error_message → toast title, error_suggestion → toast subtitle
7
+ * - Success responses: message toast title, suggestion → toast subtitle
8
+ * ------------------------------------------------------------------------------------------------
9
+ */
10
+
11
+ /**
12
+ * Standard error response returned by apiResponse.helper functions.
13
+ * The frontend shows error_message and error_suggestion in a toast.error().
14
+ */
15
+ export interface ErrorApiResponseI {
16
+ error_code: number | string
17
+ error_type:
10
18
  | 'not_identified'
11
19
  | 'invalid_request'
12
20
  | 'subscription_required'
21
+ | 'not_authorized'
13
22
  | 'internal_server_error'
14
23
  | 'resource_already_exists'
15
24
  | 'not_found'
16
25
  | 'app_update_required'
26
+ | 'sequelize_validation_error'
17
27
  | string
18
- /**
19
- * A numerical code that can be used to identify the error
20
- * Ex: 401, 403, 404, 500 or L12, L13, L14
21
- */
22
- error_code?: string | number
23
- /**
24
- * A string that can be used to suggest a solution to the user
25
- * Ex: "Please check your internet connection and try again."
26
- */
27
- error_suggestion?: string
28
+ /** Describes the error, ideally in the user's language. Displayed as the toast title. */
29
+ error_message: string
30
+ /** Suggests a resolution to the user. Displayed as the toast subtitle. */
31
+ error_suggestion: string
28
32
  }
33
+
34
+ /**
35
+ * Standard success response shape for endpoints that return a confirmation with an optional message.
36
+ * The frontend shows message and suggestion in a toast.success() when present.
37
+ */
38
+ export interface SuccessApiResponseI {
39
+ success: true
40
+ /** Contextual message to display (e.g. "Félicitation !"). Displayed as the toast title. */
41
+ message?: string
42
+ /** Additional detail shown alongside message (e.g. next task info). Displayed as the toast subtitle. */
43
+ suggestion?: string
44
+ /** Optional icon name for the frontend to render alongside the message. */
45
+ iconName?: string
46
+ }
47
+
48
+ /** @deprecated Use ErrorApiResponseI instead */
49
+ export type ApiErrorI = ErrorApiResponseI
@@ -55,6 +55,68 @@ export interface GardenMapI {
55
55
  imageURL: string
56
56
  }
57
57
 
58
+ /**
59
+ * Legacy shape values accepted by the v1 route
60
+ * (`POST /selections/:slug/gardenMap/gardenZone`).
61
+ * This legacy param must remain rectangle/circle only.
62
+ */
63
+ export type GardenZoneLegacyShape = 'rectangle' | 'circle'
64
+
65
+ /**
66
+ * Visual shape identifier stored in `geometry.properties.shape`.
67
+ */
68
+ export type GardenZoneShape = 'rectangle' | 'circle' | 'polygon'
69
+
70
+ export type GardenZoneCategory = 'cultural' | 'decorative'
71
+
72
+ /**
73
+ * Inner GeoJSON Polygon geometry (coordinates ring).
74
+ */
75
+ export interface GeoJSONPolygon {
76
+ type: 'Polygon'
77
+ coordinates: number[][][]
78
+ }
79
+
80
+ /**
81
+ * Properties stored alongside the GeoJSON Feature.
82
+ * `shape` is the canonical shape identifier.
83
+ * Shape-specific fields (center, radius, radiusX, radiusY) describe the parametric definition.
84
+ * `rotation` (degrees, clockwise) and `cornerRadius` (cm) follow GeoJSON/MapBox conventions.
85
+ * `svgPath` holds the editable SVG path string for Bézier polygon rendering.
86
+ */
87
+ export interface GeoJSONFeatureProperties {
88
+ shape: GardenZoneShape
89
+ /** Rotation in degrees, clockwise. GeoJSON convention name. */
90
+ rotation?: number
91
+ /** Corner radius in cm. MapBox convention name. */
92
+ cornerRadius?: number
93
+ /** SVG path string with Bézier curves for polygon rendering. */
94
+ svgPath?: string
95
+ /** Center point [x, y] in cm for circle/ellipse shapes. */
96
+ center?: [number, number]
97
+ /** Radius in cm for circle shapes. */
98
+ radius?: number
99
+ /** Horizontal radius in cm for ellipse shapes. */
100
+ radiusX?: number
101
+ /** Vertical radius in cm for ellipse shapes. */
102
+ radiusY?: number
103
+ }
104
+
105
+ /**
106
+ * GeoJSON Feature wrapping a Polygon geometry with shape properties.
107
+ * This is the canonical storage format for all garden zone geometries.
108
+ *
109
+ * - `properties` holds the parametric definition (shape, rotation, radii, svgPath)
110
+ * - `geometry` holds the computed polygon coordinates for calculations
111
+ *
112
+ * GeoJSON is the truth (for logic), SVG is the projection (for display and editing).
113
+ */
114
+ export interface GeoJSONFeature {
115
+ type: 'Feature'
116
+ properties: GeoJSONFeatureProperties
117
+ geometry: GeoJSONPolygon
118
+ }
119
+
58
120
  export interface GardenZoneI {
59
121
  id: number
60
122
  name: string | null
@@ -62,7 +124,15 @@ export interface GardenZoneI {
62
124
  widthInMeters: number
63
125
  heightInMeters: number
64
126
  diameterInMeters: number
65
- shape: 'rectangle' | 'circle'
127
+ shape: GardenZoneShape
128
+ /**
129
+ * Virtual field — the actual visual shape derived from geometry.properties.shape,
130
+ * falling back to the DB shape column for legacy zones.
131
+ */
132
+ geometryShape: GardenZoneShape
133
+ geometry?: GeoJSONFeature | null
134
+ category: GardenZoneCategory
135
+ backgroundImage: string | null
66
136
  xPosition: number
67
137
  yPosition: number
68
138
  zIndex: number
package/src/home.api.d.ts CHANGED
@@ -148,18 +148,23 @@ export namespace HOME {
148
148
  totalStepsCount: number
149
149
  }
150
150
 
151
- /** Minimal plant info for preview display in grouped tasks */
151
+ /** Minimal plant info for preview display (e.g. parent plant in grouped tasks) */
152
152
  export interface TaskPlantPreviewI {
153
153
  name: string
154
154
  slug: string
155
155
  imageURL?: string | null
156
156
  }
157
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
+
158
163
  /** Family group info when multiple plants share the same task */
159
164
  export interface TaskFamilyGroupI {
160
165
  familyName: string
161
166
  plantsCount: number
162
- plants: TaskPlantPreviewI[]
167
+ plants: TaskFamilyPlantPreviewI[]
163
168
  }
164
169
 
165
170
  export interface UpcomingTaskI {
@@ -175,6 +180,7 @@ export namespace HOME {
175
180
  }
176
181
 
177
182
  export interface UpcomingTaskAdviceI {
183
+ /** @deprecated Since 1.9.10, this field is always `''`. */
178
184
  content: string
179
185
  taskName: string
180
186
  plantName: string
package/src/index.ts CHANGED
@@ -1,30 +1,32 @@
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
- import * as PlantsAPI from './plants.api'
18
- import * as UsersAPI from './users.api'
19
- import * as SessionsAPI from './sessions.api'
20
- import * as HomeAPI from './home.api'
21
- import * as PagesAPI from './pages.api'
22
-
23
- // Allow access to the API namespaces without conflicts
24
- export namespace API {
25
- export import PLANTS = PlantsAPI
26
- export import USERS = UsersAPI
27
- export import SESSIONS = SessionsAPI
28
- export import HOME = HomeAPI
29
- export import PAGES = PagesAPI
30
- }
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
+ import * as PlantsAPI from './plants.api'
18
+ import * as UsersAPI from './users.api'
19
+ import * as SessionsAPI from './sessions.api'
20
+ import * as HomeAPI from './home.api'
21
+ import * as PagesAPI from './pages.api'
22
+ import * as PaymentsAPI from './payments.api'
23
+
24
+ // Allow access to the API namespaces without conflicts
25
+ export namespace API {
26
+ export import PLANTS = PlantsAPI
27
+ export import USERS = UsersAPI
28
+ export import SESSIONS = SessionsAPI
29
+ export import HOME = HomeAPI
30
+ export import PAGES = PagesAPI
31
+ export import PAYMENTS = PaymentsAPI
32
+ }
@@ -0,0 +1,17 @@
1
+ export namespace PAYMENTS {
2
+ export namespace GET {
3
+ export interface Request {
4
+ params: {
5
+ checkoutSessionId: string
6
+ }
7
+ }
8
+
9
+ export interface Response {
10
+ amount: number
11
+ category: 'Analysis' | 'Subscription'
12
+ email: string
13
+ member_id: number | null
14
+ productType: 'analysis' | 'monthlySubscription' | 'yearlySubscription' | 'fiveYearLicense' | null
15
+ }
16
+ }
17
+ }
@@ -80,7 +80,7 @@ export namespace PLANTS {
80
80
  spaceBetweenSeedMax?: number | null
81
81
  spaceBetweenAlleyMin?: number | null
82
82
  spaceBetweenAlleyMax?: number | null
83
- weeksToMaturity?: number | null
83
+ daysToMaturity?: number | null
84
84
  indoorSeeding?: boolean
85
85
  outdoorSeeding?: boolean
86
86
  sunRequirements?: 'partialShade' | 'fullSun' | 'fullShade' | null
package/src/task.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import type { SuccessApiResponseI } from './apiError'
2
+
1
3
  export interface TaskI {
2
4
  id: number
3
5
  name: string
@@ -10,6 +12,8 @@ export interface TaskI {
10
12
  colourCode: string
11
13
  iconName?: string
12
14
  private: boolean
15
+ isDone: boolean
16
+ doneAt?: Date
13
17
  }
14
18
 
15
19
  /**
@@ -27,6 +31,16 @@ export interface TaskTagI {
27
31
  iconName?: string
28
32
  }
29
33
 
34
+ /**
35
+ * Response returned when one or more tasks are marked as done.
36
+ * Extends SuccessApiResponseI for standard message/suggestion fields.
37
+ * Keys are plant slugs, values are the full updated task list for that plant selection.
38
+ * Single completion returns a record with one entry; bulk returns one entry per plant.
39
+ */
40
+ export interface CompleteTaskResponseI extends SuccessApiResponseI {
41
+ updatedTasksByPlant: Record<string, TaskI[]>
42
+ }
43
+
30
44
  /**
31
45
  * Data used to create or edit a task
32
46
  */
@@ -1,122 +1,136 @@
1
- import type { DeviceDataI } from './device.d'
2
- import type { MemberI as MemberDataI } from './member.d'
3
- import type { SelectionI } from './selection.d'
4
- import type { PlantI } from './plant.d'
5
-
6
- interface RequestHeaders {
7
- 'x-session-token': string
8
- 'x-native-app-version'?: string
9
- 'x-application-type'?: 'react-native' | 'web'
10
- }
11
-
12
- export namespace USERS {
13
- export namespace GET {
14
- export interface Request {
15
- headers: RequestHeaders
16
- params: {
17
- scopes: ('unreadNotificationsCount' | 'coordinates')[]
18
- }
19
- }
20
- export type Response = MemberDataI & {
21
- unreadAlertsCount?: number
22
- }
23
- }
24
- export namespace DEVICES {
25
- export interface Request {
26
- headers: RequestHeaders
27
- body: {
28
- /** @see DeviceDataI */
29
- userAgent?: DeviceDataI['userAgent']
30
- platform?: DeviceDataI['platform']
31
- version?: DeviceDataI['version']
32
- model?: DeviceDataI['model']
33
- name?: DeviceDataI['name']
34
- appVersion?: DeviceDataI['appVersion']
35
- pushKey?: DeviceDataI['pushKey']
36
- apnsToken?: DeviceDataI['apnsToken']
37
- fcmToken?: DeviceDataI['fcmToken']
38
- webPushEndpoint?: DeviceDataI['webPushEndpoint']
39
- webPushP256dh?: DeviceDataI['webPushP256dh']
40
- webPushAuth?: DeviceDataI['webPushAuth']
41
- webPushSubscription?: DeviceDataI['webPushSubscription']
42
- }
43
- }
44
- export type Response = DeviceDataI
45
- }
46
- export namespace RECOMMENDATIONS {
47
- export type ComponentType = 'PlantCarousel' | 'SelectionCarousel' | 'HeroCardsCarousel' | 'YourSelection'
48
-
49
- interface BaseRecommendation {
50
- id: string
51
- componentType: ComponentType
52
- title?: string
53
- subtitle?: string
54
- cardsVisible?: number
55
- }
56
-
57
- export interface PlantCarouselRecommendation extends BaseRecommendation {
58
- componentType: 'PlantCarousel'
59
- selection: SelectionI & { Plants?: PlantI[] }
60
- displayRanking?: boolean
61
- }
62
-
63
- export interface SelectionCarouselRecommendation extends BaseRecommendation {
64
- componentType: 'SelectionCarousel'
65
- selections: SelectionI[]
66
- displayRanking?: boolean
67
- }
68
-
69
- export interface HeroCardsCarouselRecommendation extends BaseRecommendation {
70
- componentType: 'HeroCardsCarousel'
71
- selections: SelectionI[]
72
- }
73
-
74
- export interface YourSelectionRecommendation extends BaseRecommendation {
75
- componentType: 'YourSelection'
76
- }
77
-
78
- export type RecommendationI =
79
- | PlantCarouselRecommendation
80
- | SelectionCarouselRecommendation
81
- | HeroCardsCarouselRecommendation
82
- | YourSelectionRecommendation
83
-
84
- export interface Request {
85
- headers: RequestHeaders
86
- }
87
-
88
- export type Response = RecommendationI[]
89
- }
90
- export namespace UPDATE {
91
- export interface Request {
92
- headers: RequestHeaders
93
- body: {
94
- city?: string
95
- lastFreezingDate?: string | Date
96
- firstFreezingDate?: string | Date
97
- moveDatesRequested?: boolean
98
- lastFertilizerIdChosen?: number
99
- lastOrganicMatterPercentage?: number
100
- unitSystem?: 'imperial' | 'metric'
101
- gardenZoneTimelessPreference?: boolean
102
- }
103
- }
104
- export type Response = MemberDataI
105
- }
106
- export namespace GIFT_CARDS {
107
- export namespace REDEEM {
108
- export interface Request {
109
- headers: RequestHeaders
110
- body: {
111
- code: string
112
- }
113
- }
114
- export interface Response {
115
- success: boolean
116
- message?: string
117
- error?: string
118
- error_message?: string
119
- }
120
- }
121
- }
122
- }
1
+ import type { DeviceDataI } from './device.d'
2
+ import type { MemberI as MemberDataI } from './member.d'
3
+ import type { SelectionI } from './selection.d'
4
+ import type { PlantI } from './plant.d'
5
+
6
+ interface RequestHeaders {
7
+ 'x-session-token': string
8
+ 'x-native-app-version'?: string
9
+ 'x-application-type'?: 'react-native' | 'web'
10
+ }
11
+
12
+ export namespace USERS {
13
+ export namespace GET {
14
+ export interface Request {
15
+ headers: RequestHeaders
16
+ params: {
17
+ scopes: ('unreadNotificationsCount' | 'coordinates')[]
18
+ }
19
+ }
20
+ export type Response = MemberDataI & {
21
+ unreadAlertsCount?: number
22
+ }
23
+ }
24
+ export namespace DEVICES {
25
+ export interface Request {
26
+ headers: RequestHeaders
27
+ body: {
28
+ /** @see DeviceDataI */
29
+ userAgent?: DeviceDataI['userAgent']
30
+ platform?: DeviceDataI['platform']
31
+ version?: DeviceDataI['version']
32
+ model?: DeviceDataI['model']
33
+ name?: DeviceDataI['name']
34
+ appVersion?: DeviceDataI['appVersion']
35
+ pushKey?: DeviceDataI['pushKey']
36
+ apnsToken?: DeviceDataI['apnsToken']
37
+ fcmToken?: DeviceDataI['fcmToken']
38
+ webPushEndpoint?: DeviceDataI['webPushEndpoint']
39
+ webPushP256dh?: DeviceDataI['webPushP256dh']
40
+ webPushAuth?: DeviceDataI['webPushAuth']
41
+ webPushSubscription?: DeviceDataI['webPushSubscription']
42
+ }
43
+ }
44
+ export type Response = DeviceDataI
45
+ }
46
+ export namespace RECOMMENDATIONS {
47
+ export type ComponentType = 'PlantCarousel' | 'SelectionCarousel' | 'HeroCardsCarousel' | 'YourSelection'
48
+
49
+ interface BaseRecommendation {
50
+ id: string
51
+ componentType: ComponentType
52
+ title?: string
53
+ subtitle?: string
54
+ cardsVisible?: number
55
+ }
56
+
57
+ export interface PlantCarouselRecommendation extends BaseRecommendation {
58
+ componentType: 'PlantCarousel'
59
+ selection: SelectionI & { Plants?: PlantI[] }
60
+ displayRanking?: boolean
61
+ }
62
+
63
+ export interface SelectionCarouselRecommendation extends BaseRecommendation {
64
+ componentType: 'SelectionCarousel'
65
+ selections: SelectionI[]
66
+ displayRanking?: boolean
67
+ }
68
+
69
+ export interface HeroCardsCarouselRecommendation extends BaseRecommendation {
70
+ componentType: 'HeroCardsCarousel'
71
+ selections: SelectionI[]
72
+ }
73
+
74
+ export interface YourSelectionRecommendation extends BaseRecommendation {
75
+ componentType: 'YourSelection'
76
+ }
77
+
78
+ export interface ThemedRecommendationI {
79
+ id: string
80
+ label: string
81
+ icon: string
82
+ title?: string
83
+ subtitle?: string
84
+ selections: SelectionI[]
85
+ cardsVisible?: number
86
+ displayRanking?: boolean
87
+ }
88
+
89
+ export type RecommendationI =
90
+ | PlantCarouselRecommendation
91
+ | SelectionCarouselRecommendation
92
+ | HeroCardsCarouselRecommendation
93
+ | YourSelectionRecommendation
94
+
95
+ export interface Request {
96
+ headers: RequestHeaders
97
+ }
98
+
99
+ export interface Response {
100
+ recommendations: RecommendationI[]
101
+ themedRecommendations: ThemedRecommendationI[]
102
+ }
103
+ }
104
+ export namespace UPDATE {
105
+ export interface Request {
106
+ headers: RequestHeaders
107
+ body: {
108
+ city?: string
109
+ lastFreezingDate?: string | Date
110
+ firstFreezingDate?: string | Date
111
+ moveDatesRequested?: boolean
112
+ lastFertilizerIdChosen?: number
113
+ lastOrganicMatterPercentage?: number
114
+ unitSystem?: 'imperial' | 'metric'
115
+ gardenZoneTimelessPreference?: boolean
116
+ }
117
+ }
118
+ export type Response = MemberDataI
119
+ }
120
+ export namespace GIFT_CARDS {
121
+ export namespace REDEEM {
122
+ export interface Request {
123
+ headers: RequestHeaders
124
+ body: {
125
+ code: string
126
+ }
127
+ }
128
+ export interface Response {
129
+ success: boolean
130
+ message?: string
131
+ error?: string
132
+ error_message?: string
133
+ }
134
+ }
135
+ }
136
+ }