@automattic/jetpack-ai-client 0.14.6 → 0.15.0

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.
Files changed (128) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/build/ask-question/sync.d.ts +2 -8
  3. package/build/ask-question/sync.js +20 -19
  4. package/build/hooks/use-image-generator/index.js +1 -1
  5. package/build/hooks/use-save-to-media-library/index.d.ts +12 -0
  6. package/build/hooks/use-save-to-media-library/index.js +74 -0
  7. package/build/index.d.ts +2 -0
  8. package/build/index.js +5 -0
  9. package/build/libs/index.d.ts +1 -1
  10. package/build/libs/index.js +1 -1
  11. package/build/libs/markdown/index.d.ts +2 -2
  12. package/build/libs/markdown/index.js +2 -2
  13. package/build/libs/markdown/markdown-to-html.d.ts +8 -1
  14. package/build/libs/markdown/markdown-to-html.js +10 -1
  15. package/build/logo-generator/assets/icons/ai.d.ts +6 -0
  16. package/build/logo-generator/assets/icons/ai.js +8 -0
  17. package/build/logo-generator/assets/icons/check.d.ts +6 -0
  18. package/build/logo-generator/assets/icons/check.js +8 -0
  19. package/build/logo-generator/assets/icons/logo.d.ts +6 -0
  20. package/build/logo-generator/assets/icons/logo.js +8 -0
  21. package/build/logo-generator/assets/icons/media.d.ts +6 -0
  22. package/build/logo-generator/assets/icons/media.js +8 -0
  23. package/build/logo-generator/components/feature-fetch-failure-screen.d.ts +8 -0
  24. package/build/logo-generator/components/feature-fetch-failure-screen.js +10 -0
  25. package/build/logo-generator/components/first-load-screen.d.ts +5 -0
  26. package/build/logo-generator/components/first-load-screen.js +16 -0
  27. package/build/logo-generator/components/generator-modal.d.ts +7 -0
  28. package/build/logo-generator/components/generator-modal.js +184 -0
  29. package/build/logo-generator/components/history-carousel.d.ts +6 -0
  30. package/build/logo-generator/components/history-carousel.js +36 -0
  31. package/build/logo-generator/components/image-loader.d.ts +7 -0
  32. package/build/logo-generator/components/image-loader.js +12 -0
  33. package/build/logo-generator/components/logo-presenter.d.ts +4 -0
  34. package/build/logo-generator/components/logo-presenter.js +106 -0
  35. package/build/logo-generator/components/prompt.d.ts +5 -0
  36. package/build/logo-generator/components/prompt.js +96 -0
  37. package/build/logo-generator/components/upgrade-nudge.d.ts +2 -0
  38. package/build/logo-generator/components/upgrade-nudge.js +30 -0
  39. package/build/logo-generator/components/upgrade-screen.d.ts +9 -0
  40. package/build/logo-generator/components/upgrade-screen.js +24 -0
  41. package/build/logo-generator/components/visit-site-banner.d.ts +10 -0
  42. package/build/logo-generator/components/visit-site-banner.js +16 -0
  43. package/build/logo-generator/constants.d.ts +16 -0
  44. package/build/logo-generator/constants.js +19 -0
  45. package/build/logo-generator/hooks/use-checkout.d.ts +4 -0
  46. package/build/logo-generator/hooks/use-checkout.js +26 -0
  47. package/build/logo-generator/hooks/use-logo-generator.d.ts +46 -0
  48. package/build/logo-generator/hooks/use-logo-generator.js +286 -0
  49. package/build/logo-generator/hooks/use-request-errors.d.ts +16 -0
  50. package/build/logo-generator/hooks/use-request-errors.js +46 -0
  51. package/build/logo-generator/index.d.ts +1 -0
  52. package/build/logo-generator/index.js +1 -0
  53. package/build/logo-generator/lib/logo-storage.d.ts +58 -0
  54. package/build/logo-generator/lib/logo-storage.js +123 -0
  55. package/build/logo-generator/lib/media-exists.d.ts +12 -0
  56. package/build/logo-generator/lib/media-exists.js +33 -0
  57. package/build/logo-generator/lib/set-site-logo.d.ts +13 -0
  58. package/build/logo-generator/lib/set-site-logo.js +26 -0
  59. package/build/logo-generator/lib/wpcom-limited-request.d.ts +7 -0
  60. package/build/logo-generator/lib/wpcom-limited-request.js +33 -0
  61. package/build/logo-generator/store/actions.d.ts +105 -0
  62. package/build/logo-generator/store/actions.js +193 -0
  63. package/build/logo-generator/store/constants.d.ts +44 -0
  64. package/build/logo-generator/store/constants.js +44 -0
  65. package/build/logo-generator/store/index.d.ts +1 -0
  66. package/build/logo-generator/store/index.js +19 -0
  67. package/build/logo-generator/store/initial-state.d.ts +3 -0
  68. package/build/logo-generator/store/initial-state.js +40 -0
  69. package/build/logo-generator/store/reducer.d.ts +347 -0
  70. package/build/logo-generator/store/reducer.js +293 -0
  71. package/build/logo-generator/store/selectors.d.ts +119 -0
  72. package/build/logo-generator/store/selectors.js +173 -0
  73. package/build/logo-generator/store/types.d.ts +164 -0
  74. package/build/logo-generator/store/types.js +1 -0
  75. package/build/logo-generator/types.d.ts +82 -0
  76. package/build/logo-generator/types.js +1 -0
  77. package/build/types.d.ts +6 -0
  78. package/package.json +5 -3
  79. package/src/ask-question/sync.ts +22 -27
  80. package/src/hooks/use-image-generator/index.ts +1 -1
  81. package/src/hooks/use-save-to-media-library/index.ts +95 -0
  82. package/src/index.ts +6 -0
  83. package/src/libs/index.ts +1 -0
  84. package/src/libs/markdown/index.ts +2 -2
  85. package/src/libs/markdown/markdown-to-html.ts +20 -3
  86. package/src/logo-generator/assets/icons/ai.tsx +21 -0
  87. package/src/logo-generator/assets/icons/check.tsx +23 -0
  88. package/src/logo-generator/assets/icons/icons.scss +5 -0
  89. package/src/logo-generator/assets/icons/logo.tsx +23 -0
  90. package/src/logo-generator/assets/icons/media.tsx +24 -0
  91. package/src/logo-generator/assets/images/jetpack-logo.svg +4 -0
  92. package/src/logo-generator/assets/images/loader.gif +0 -0
  93. package/src/logo-generator/assets/index.d.ts +3 -0
  94. package/src/logo-generator/components/feature-fetch-failure-screen.tsx +35 -0
  95. package/src/logo-generator/components/first-load-screen.scss +12 -0
  96. package/src/logo-generator/components/first-load-screen.tsx +32 -0
  97. package/src/logo-generator/components/generator-modal.scss +92 -0
  98. package/src/logo-generator/components/generator-modal.tsx +291 -0
  99. package/src/logo-generator/components/history-carousel.scss +36 -0
  100. package/src/logo-generator/components/history-carousel.tsx +57 -0
  101. package/src/logo-generator/components/image-loader.tsx +22 -0
  102. package/src/logo-generator/components/logo-presenter.scss +116 -0
  103. package/src/logo-generator/components/logo-presenter.tsx +234 -0
  104. package/src/logo-generator/components/prompt.scss +102 -0
  105. package/src/logo-generator/components/prompt.tsx +211 -0
  106. package/src/logo-generator/components/upgrade-nudge.scss +43 -0
  107. package/src/logo-generator/components/upgrade-nudge.tsx +58 -0
  108. package/src/logo-generator/components/upgrade-screen.tsx +67 -0
  109. package/src/logo-generator/components/visit-site-banner.scss +29 -0
  110. package/src/logo-generator/components/visit-site-banner.tsx +50 -0
  111. package/src/logo-generator/constants.ts +22 -0
  112. package/src/logo-generator/hooks/use-checkout.ts +37 -0
  113. package/src/logo-generator/hooks/use-logo-generator.ts +389 -0
  114. package/src/logo-generator/hooks/use-request-errors.ts +70 -0
  115. package/src/logo-generator/index.ts +1 -0
  116. package/src/logo-generator/lib/logo-storage.ts +166 -0
  117. package/src/logo-generator/lib/media-exists.ts +42 -0
  118. package/src/logo-generator/lib/set-site-logo.ts +32 -0
  119. package/src/logo-generator/lib/wpcom-limited-request.ts +41 -0
  120. package/src/logo-generator/store/actions.ts +251 -0
  121. package/src/logo-generator/store/constants.ts +49 -0
  122. package/src/logo-generator/store/index.ts +25 -0
  123. package/src/logo-generator/store/initial-state.ts +43 -0
  124. package/src/logo-generator/store/reducer.ts +387 -0
  125. package/src/logo-generator/store/selectors.ts +201 -0
  126. package/src/logo-generator/store/types.ts +207 -0
  127. package/src/logo-generator/types.ts +97 -0
  128. package/src/types.ts +8 -0
@@ -0,0 +1,347 @@
1
+ import type { AiFeatureStateProps, LogoGeneratorStateProp, RequestError } from './types.js';
2
+ import type { SiteDetails } from '../types.js';
3
+ /**
4
+ * Reducer for the Logo Generator store.
5
+ *
6
+ * @param {LogoGeneratorStateProp} state - The current state
7
+ * @param {object} action - The action to apply, as described by the properties below
8
+ * @param {string} action.type - The action type
9
+ * @param {AiFeatureStateProps} action.feature - The AI Assistant feature state
10
+ * @param {number} action.count - The number of requests to increase the counter by
11
+ * @param {boolean} action.requireUpgrade - Whether an upgrade is required
12
+ * @param {boolean} action.tierPlansEnabled - Whether tier plans are enabled
13
+ * @param {SiteDetails} action.siteDetails - The site details
14
+ * @param {number} action.selectedLogoIndex - The selected logo index
15
+ * @param {boolean} action.isSavingLogoToLibrary - Whether a logo is being saved to the library
16
+ * @param {boolean} action.isApplyingLogo - Whether a logo is being applied
17
+ * @param {object} action.logo - The logo to save, as described by the properties below
18
+ * @param {string} action.logo.url - The logo URL
19
+ * @param {string} action.logo.description - The logo description
20
+ * @param {number} action.mediaId - The media ID from backend
21
+ * @param {string} action.url - The URL to save
22
+ * @param {boolean} action.isRequestingImage - Whether an image is being requested
23
+ * @param {boolean} action.isEnhancingPrompt - Whether a prompt enhancement is being requested
24
+ * @param {Array< { url: string; description: string; mediaId?: number } >} action.history - The logo history
25
+ * @param {RequestError} action.error - The error to set
26
+ * @param {string} action.context - The context where the tool is being used
27
+ * @returns {LogoGeneratorStateProp} The new state
28
+ */
29
+ export default function reducer(state: LogoGeneratorStateProp, action: {
30
+ type: string;
31
+ feature?: AiFeatureStateProps;
32
+ count?: number;
33
+ requireUpgrade?: boolean;
34
+ tierPlansEnabled?: boolean;
35
+ siteDetails?: SiteDetails;
36
+ selectedLogoIndex?: number;
37
+ isSavingLogoToLibrary?: boolean;
38
+ isApplyingLogo?: boolean;
39
+ logo?: {
40
+ url: string;
41
+ description: string;
42
+ };
43
+ mediaId?: number;
44
+ url?: string;
45
+ isRequestingImage?: boolean;
46
+ isEnhancingPrompt?: boolean;
47
+ history?: Array<{
48
+ url: string;
49
+ description: string;
50
+ mediaId?: number;
51
+ }>;
52
+ error?: RequestError;
53
+ context?: string;
54
+ }): {
55
+ features: {
56
+ aiAssistantFeature: {
57
+ isOverLimit: boolean;
58
+ requestsCount: number;
59
+ requireUpgrade: boolean;
60
+ usagePeriod: {
61
+ currentStart: string;
62
+ nextStart: string;
63
+ requestsCount: number;
64
+ } | {
65
+ requestsCount: number;
66
+ };
67
+ hasFeature: boolean;
68
+ requestsLimit: number;
69
+ errorMessage?: string;
70
+ errorCode?: string;
71
+ upgradeType: import("./types.js").UpgradeTypeProp;
72
+ currentTier?: import("./types.js").TierProp;
73
+ nextTier?: import("./types.js").TierProp;
74
+ tierPlansEnabled?: boolean;
75
+ costs?: {
76
+ 'jetpack-ai-logo-generator': {
77
+ logo: number;
78
+ };
79
+ };
80
+ _meta?: {
81
+ isRequesting: boolean;
82
+ asyncRequestCountdown: number;
83
+ asyncRequestTimerId: number;
84
+ isRequestingImage: boolean;
85
+ };
86
+ };
87
+ };
88
+ _meta?: {
89
+ isSavingLogoToLibrary: boolean;
90
+ isApplyingLogo: boolean;
91
+ isRequestingImage: boolean;
92
+ isEnhancingPrompt: boolean;
93
+ featureFetchError?: RequestError;
94
+ firstLogoPromptFetchError?: RequestError;
95
+ enhancePromptFetchError?: RequestError;
96
+ logoFetchError?: RequestError;
97
+ saveToLibraryError?: RequestError;
98
+ logoUpdateError?: RequestError;
99
+ context: string;
100
+ };
101
+ siteDetails?: SiteDetails | Record<string, never>;
102
+ history: import("./types.js").Logo[];
103
+ selectedLogoIndex: number;
104
+ } | {
105
+ history: {
106
+ url: string;
107
+ description: string;
108
+ }[];
109
+ selectedLogoIndex: number;
110
+ _meta?: {
111
+ isSavingLogoToLibrary: boolean;
112
+ isApplyingLogo: boolean;
113
+ isRequestingImage: boolean;
114
+ isEnhancingPrompt: boolean;
115
+ featureFetchError?: RequestError;
116
+ firstLogoPromptFetchError?: RequestError;
117
+ enhancePromptFetchError?: RequestError;
118
+ logoFetchError?: RequestError;
119
+ saveToLibraryError?: RequestError;
120
+ logoUpdateError?: RequestError;
121
+ context: string;
122
+ };
123
+ siteDetails?: SiteDetails | Record<string, never>;
124
+ features: {
125
+ aiAssistantFeature?: AiFeatureStateProps;
126
+ };
127
+ } | {
128
+ _meta: {
129
+ isSavingLogoToLibrary: boolean;
130
+ isApplyingLogo?: boolean;
131
+ isRequestingImage?: boolean;
132
+ isEnhancingPrompt?: boolean;
133
+ featureFetchError?: RequestError;
134
+ firstLogoPromptFetchError?: RequestError;
135
+ enhancePromptFetchError?: RequestError;
136
+ logoFetchError?: RequestError;
137
+ saveToLibraryError?: RequestError;
138
+ logoUpdateError?: RequestError;
139
+ context?: string;
140
+ };
141
+ siteDetails?: SiteDetails | Record<string, never>;
142
+ features: {
143
+ aiAssistantFeature?: AiFeatureStateProps;
144
+ };
145
+ history: import("./types.js").Logo[];
146
+ selectedLogoIndex: number;
147
+ } | {
148
+ _meta: {
149
+ isApplyingLogo: boolean;
150
+ isSavingLogoToLibrary?: boolean;
151
+ isRequestingImage?: boolean;
152
+ isEnhancingPrompt?: boolean;
153
+ featureFetchError?: RequestError;
154
+ firstLogoPromptFetchError?: RequestError;
155
+ enhancePromptFetchError?: RequestError;
156
+ logoFetchError?: RequestError;
157
+ saveToLibraryError?: RequestError;
158
+ logoUpdateError?: RequestError;
159
+ context?: string;
160
+ };
161
+ siteDetails?: SiteDetails | Record<string, never>;
162
+ features: {
163
+ aiAssistantFeature?: AiFeatureStateProps;
164
+ };
165
+ history: import("./types.js").Logo[];
166
+ selectedLogoIndex: number;
167
+ } | {
168
+ _meta: {
169
+ isRequestingImage: boolean;
170
+ isSavingLogoToLibrary?: boolean;
171
+ isApplyingLogo?: boolean;
172
+ isEnhancingPrompt?: boolean;
173
+ featureFetchError?: RequestError;
174
+ firstLogoPromptFetchError?: RequestError;
175
+ enhancePromptFetchError?: RequestError;
176
+ logoFetchError?: RequestError;
177
+ saveToLibraryError?: RequestError;
178
+ logoUpdateError?: RequestError;
179
+ context?: string;
180
+ };
181
+ siteDetails?: SiteDetails | Record<string, never>;
182
+ features: {
183
+ aiAssistantFeature?: AiFeatureStateProps;
184
+ };
185
+ history: import("./types.js").Logo[];
186
+ selectedLogoIndex: number;
187
+ } | {
188
+ _meta: {
189
+ isEnhancingPrompt: boolean;
190
+ isSavingLogoToLibrary?: boolean;
191
+ isApplyingLogo?: boolean;
192
+ isRequestingImage?: boolean;
193
+ featureFetchError?: RequestError;
194
+ firstLogoPromptFetchError?: RequestError;
195
+ enhancePromptFetchError?: RequestError;
196
+ logoFetchError?: RequestError;
197
+ saveToLibraryError?: RequestError;
198
+ logoUpdateError?: RequestError;
199
+ context?: string;
200
+ };
201
+ siteDetails?: SiteDetails | Record<string, never>;
202
+ features: {
203
+ aiAssistantFeature?: AiFeatureStateProps;
204
+ };
205
+ history: import("./types.js").Logo[];
206
+ selectedLogoIndex: number;
207
+ } | {
208
+ _meta: {
209
+ featureFetchError: RequestError;
210
+ isSavingLogoToLibrary?: boolean;
211
+ isApplyingLogo?: boolean;
212
+ isRequestingImage?: boolean;
213
+ isEnhancingPrompt?: boolean;
214
+ firstLogoPromptFetchError?: RequestError;
215
+ enhancePromptFetchError?: RequestError;
216
+ logoFetchError?: RequestError;
217
+ saveToLibraryError?: RequestError;
218
+ logoUpdateError?: RequestError;
219
+ context?: string;
220
+ };
221
+ siteDetails?: SiteDetails | Record<string, never>;
222
+ features: {
223
+ aiAssistantFeature?: AiFeatureStateProps;
224
+ };
225
+ history: import("./types.js").Logo[];
226
+ selectedLogoIndex: number;
227
+ } | {
228
+ _meta: {
229
+ firstLogoPromptFetchError: RequestError;
230
+ isSavingLogoToLibrary?: boolean;
231
+ isApplyingLogo?: boolean;
232
+ isRequestingImage?: boolean;
233
+ isEnhancingPrompt?: boolean;
234
+ featureFetchError?: RequestError;
235
+ enhancePromptFetchError?: RequestError;
236
+ logoFetchError?: RequestError;
237
+ saveToLibraryError?: RequestError;
238
+ logoUpdateError?: RequestError;
239
+ context?: string;
240
+ };
241
+ siteDetails?: SiteDetails | Record<string, never>;
242
+ features: {
243
+ aiAssistantFeature?: AiFeatureStateProps;
244
+ };
245
+ history: import("./types.js").Logo[];
246
+ selectedLogoIndex: number;
247
+ } | {
248
+ _meta: {
249
+ enhancePromptFetchError: RequestError;
250
+ isSavingLogoToLibrary?: boolean;
251
+ isApplyingLogo?: boolean;
252
+ isRequestingImage?: boolean;
253
+ isEnhancingPrompt?: boolean;
254
+ featureFetchError?: RequestError;
255
+ firstLogoPromptFetchError?: RequestError;
256
+ logoFetchError?: RequestError;
257
+ saveToLibraryError?: RequestError;
258
+ logoUpdateError?: RequestError;
259
+ context?: string;
260
+ };
261
+ siteDetails?: SiteDetails | Record<string, never>;
262
+ features: {
263
+ aiAssistantFeature?: AiFeatureStateProps;
264
+ };
265
+ history: import("./types.js").Logo[];
266
+ selectedLogoIndex: number;
267
+ } | {
268
+ _meta: {
269
+ logoFetchError: RequestError;
270
+ isSavingLogoToLibrary?: boolean;
271
+ isApplyingLogo?: boolean;
272
+ isRequestingImage?: boolean;
273
+ isEnhancingPrompt?: boolean;
274
+ featureFetchError?: RequestError;
275
+ firstLogoPromptFetchError?: RequestError;
276
+ enhancePromptFetchError?: RequestError;
277
+ saveToLibraryError?: RequestError;
278
+ logoUpdateError?: RequestError;
279
+ context?: string;
280
+ };
281
+ siteDetails?: SiteDetails | Record<string, never>;
282
+ features: {
283
+ aiAssistantFeature?: AiFeatureStateProps;
284
+ };
285
+ history: import("./types.js").Logo[];
286
+ selectedLogoIndex: number;
287
+ } | {
288
+ _meta: {
289
+ saveToLibraryError: RequestError;
290
+ isSavingLogoToLibrary?: boolean;
291
+ isApplyingLogo?: boolean;
292
+ isRequestingImage?: boolean;
293
+ isEnhancingPrompt?: boolean;
294
+ featureFetchError?: RequestError;
295
+ firstLogoPromptFetchError?: RequestError;
296
+ enhancePromptFetchError?: RequestError;
297
+ logoFetchError?: RequestError;
298
+ logoUpdateError?: RequestError;
299
+ context?: string;
300
+ };
301
+ siteDetails?: SiteDetails | Record<string, never>;
302
+ features: {
303
+ aiAssistantFeature?: AiFeatureStateProps;
304
+ };
305
+ history: import("./types.js").Logo[];
306
+ selectedLogoIndex: number;
307
+ } | {
308
+ _meta: {
309
+ logoUpdateError: RequestError;
310
+ isSavingLogoToLibrary?: boolean;
311
+ isApplyingLogo?: boolean;
312
+ isRequestingImage?: boolean;
313
+ isEnhancingPrompt?: boolean;
314
+ featureFetchError?: RequestError;
315
+ firstLogoPromptFetchError?: RequestError;
316
+ enhancePromptFetchError?: RequestError;
317
+ logoFetchError?: RequestError;
318
+ saveToLibraryError?: RequestError;
319
+ context?: string;
320
+ };
321
+ siteDetails?: SiteDetails | Record<string, never>;
322
+ features: {
323
+ aiAssistantFeature?: AiFeatureStateProps;
324
+ };
325
+ history: import("./types.js").Logo[];
326
+ selectedLogoIndex: number;
327
+ } | {
328
+ _meta: {
329
+ context: string;
330
+ isSavingLogoToLibrary?: boolean;
331
+ isApplyingLogo?: boolean;
332
+ isRequestingImage?: boolean;
333
+ isEnhancingPrompt?: boolean;
334
+ featureFetchError?: RequestError;
335
+ firstLogoPromptFetchError?: RequestError;
336
+ enhancePromptFetchError?: RequestError;
337
+ logoFetchError?: RequestError;
338
+ saveToLibraryError?: RequestError;
339
+ logoUpdateError?: RequestError;
340
+ };
341
+ siteDetails?: SiteDetails | Record<string, never>;
342
+ features: {
343
+ aiAssistantFeature?: AiFeatureStateProps;
344
+ };
345
+ history: import("./types.js").Logo[];
346
+ selectedLogoIndex: number;
347
+ };
@@ -0,0 +1,293 @@
1
+ /**
2
+ * Types & Constants
3
+ */
4
+ import { DEFAULT_LOGO_COST } from '../constants.js';
5
+ import { ACTION_INCREASE_AI_ASSISTANT_REQUESTS_COUNT, ACTION_REQUEST_AI_ASSISTANT_FEATURE, ACTION_SET_AI_ASSISTANT_FEATURE_REQUIRE_UPGRADE, ACTION_STORE_AI_ASSISTANT_FEATURE, ASYNC_REQUEST_COUNTDOWN_INIT_VALUE, FREE_PLAN_REQUESTS_LIMIT, UNLIMITED_PLAN_REQUESTS_LIMIT, ACTION_SET_TIER_PLANS_ENABLED, ACTION_SET_SITE_DETAILS, ACTION_SET_SELECTED_LOGO_INDEX, ACTION_ADD_LOGO_TO_HISTORY, ACTION_SAVE_SELECTED_LOGO, ACTION_SET_IS_SAVING_LOGO_TO_LIBRARY, ACTION_SET_IS_REQUESTING_IMAGE, ACTION_SET_IS_APPLYING_LOGO, ACTION_SET_IS_ENHANCING_PROMPT, ACTION_SET_SITE_HISTORY, ACTION_SET_FEATURE_FETCH_ERROR, ACTION_SET_FIRST_LOGO_PROMPT_FETCH_ERROR, ACTION_SET_ENHANCE_PROMPT_FETCH_ERROR, ACTION_SET_LOGO_FETCH_ERROR, ACTION_SET_SAVE_TO_LIBRARY_ERROR, ACTION_SET_LOGO_UPDATE_ERROR, ACTION_SET_CONTEXT, } from './constants.js';
6
+ import INITIAL_STATE from './initial-state.js';
7
+ /**
8
+ * Reducer for the Logo Generator store.
9
+ *
10
+ * @param {LogoGeneratorStateProp} state - The current state
11
+ * @param {object} action - The action to apply, as described by the properties below
12
+ * @param {string} action.type - The action type
13
+ * @param {AiFeatureStateProps} action.feature - The AI Assistant feature state
14
+ * @param {number} action.count - The number of requests to increase the counter by
15
+ * @param {boolean} action.requireUpgrade - Whether an upgrade is required
16
+ * @param {boolean} action.tierPlansEnabled - Whether tier plans are enabled
17
+ * @param {SiteDetails} action.siteDetails - The site details
18
+ * @param {number} action.selectedLogoIndex - The selected logo index
19
+ * @param {boolean} action.isSavingLogoToLibrary - Whether a logo is being saved to the library
20
+ * @param {boolean} action.isApplyingLogo - Whether a logo is being applied
21
+ * @param {object} action.logo - The logo to save, as described by the properties below
22
+ * @param {string} action.logo.url - The logo URL
23
+ * @param {string} action.logo.description - The logo description
24
+ * @param {number} action.mediaId - The media ID from backend
25
+ * @param {string} action.url - The URL to save
26
+ * @param {boolean} action.isRequestingImage - Whether an image is being requested
27
+ * @param {boolean} action.isEnhancingPrompt - Whether a prompt enhancement is being requested
28
+ * @param {Array< { url: string; description: string; mediaId?: number } >} action.history - The logo history
29
+ * @param {RequestError} action.error - The error to set
30
+ * @param {string} action.context - The context where the tool is being used
31
+ * @returns {LogoGeneratorStateProp} The new state
32
+ */
33
+ export default function reducer(state = INITIAL_STATE, action) {
34
+ switch (action.type) {
35
+ case ACTION_REQUEST_AI_ASSISTANT_FEATURE:
36
+ return {
37
+ ...state,
38
+ _meta: {
39
+ ...(state._meta ?? {}),
40
+ // Reset the error state when requesting the feature.
41
+ featureFetchError: null,
42
+ },
43
+ features: {
44
+ ...state.features,
45
+ aiAssistantFeature: {
46
+ ...state.features.aiAssistantFeature,
47
+ _meta: {
48
+ ...state?.features?.aiAssistantFeature?._meta,
49
+ isRequesting: true,
50
+ asyncRequestCountdown: ASYNC_REQUEST_COUNTDOWN_INIT_VALUE,
51
+ asyncRequestTimerId: 0, // reset the timer id
52
+ },
53
+ },
54
+ },
55
+ };
56
+ case ACTION_STORE_AI_ASSISTANT_FEATURE: {
57
+ const defaultCosts = {
58
+ 'jetpack-ai-logo-generator': {
59
+ logo: DEFAULT_LOGO_COST,
60
+ },
61
+ };
62
+ return {
63
+ ...state,
64
+ features: {
65
+ ...state.features,
66
+ aiAssistantFeature: {
67
+ costs: defaultCosts,
68
+ ...action.feature,
69
+ // re evaluate requireUpgrade as the logo generator does not allow free usage
70
+ requireUpgrade: action.feature?.requireUpgrade || action.feature?.currentTier?.value === 0,
71
+ _meta: {
72
+ ...state?.features?.aiAssistantFeature?._meta,
73
+ isRequesting: false,
74
+ },
75
+ },
76
+ },
77
+ };
78
+ }
79
+ case ACTION_INCREASE_AI_ASSISTANT_REQUESTS_COUNT: {
80
+ // Usage Period data
81
+ const usagePeriod = state?.features?.aiAssistantFeature?.usagePeriod || { requestsCount: 0 };
82
+ // Increase requests counters
83
+ const requestsCount = (state?.features?.aiAssistantFeature?.requestsCount || 0) + (action.count ?? 1);
84
+ usagePeriod.requestsCount += action.count ?? 1;
85
+ // Current tier value
86
+ const currentTierValue = state?.features?.aiAssistantFeature?.currentTier?.value;
87
+ const isFreeTierPlan = (typeof currentTierValue === 'undefined' &&
88
+ !state?.features?.aiAssistantFeature?.hasFeature) ||
89
+ currentTierValue === 0;
90
+ const isUnlimitedTierPlan = (typeof currentTierValue === 'undefined' &&
91
+ state?.features?.aiAssistantFeature?.hasFeature) ||
92
+ currentTierValue === 1;
93
+ // Request limit defined with the current tier limit by default.
94
+ let requestsLimit = state?.features?.aiAssistantFeature?.currentTier?.limit || FREE_PLAN_REQUESTS_LIMIT;
95
+ if (isUnlimitedTierPlan) {
96
+ requestsLimit = UNLIMITED_PLAN_REQUESTS_LIMIT;
97
+ }
98
+ else if (isFreeTierPlan) {
99
+ requestsLimit = state?.features?.aiAssistantFeature?.requestsLimit;
100
+ }
101
+ const currentCount = isUnlimitedTierPlan || isFreeTierPlan // @todo: update once tier data is available
102
+ ? requestsCount
103
+ : state?.features?.aiAssistantFeature?.usagePeriod?.requestsCount || 0;
104
+ /**
105
+ * Compute the AI Assistant Feature data optimistically,
106
+ * based on the Jetpack_AI_Helper::get_ai_assistance_feature() helper.
107
+ * @see _inc/lib/class-jetpack-ai-helper.php
108
+ */
109
+ const isOverLimit = currentCount >= requestsLimit;
110
+ // highest tier holds a soft limit so requireUpgrade is false on that case (nextTier null means highest tier)
111
+ const requireUpgrade = isFreeTierPlan || (isOverLimit && state?.features?.aiAssistantFeature?.nextTier !== null);
112
+ return {
113
+ ...state,
114
+ features: {
115
+ ...state.features,
116
+ aiAssistantFeature: {
117
+ ...state.features.aiAssistantFeature,
118
+ isOverLimit,
119
+ requestsCount,
120
+ requireUpgrade,
121
+ usagePeriod: { ...usagePeriod },
122
+ },
123
+ },
124
+ };
125
+ }
126
+ case ACTION_SET_AI_ASSISTANT_FEATURE_REQUIRE_UPGRADE: {
127
+ /*
128
+ * If we require an upgrade, we are also over the limit;
129
+ * The opposite is not true, we can be over the limit without
130
+ * requiring an upgrade, for example when we are on the highest tier.
131
+ * In this case, we don't want to set isOverLimit to false.
132
+ */
133
+ return {
134
+ ...state,
135
+ features: {
136
+ ...state.features,
137
+ aiAssistantFeature: {
138
+ ...state.features.aiAssistantFeature,
139
+ requireUpgrade: action.requireUpgrade,
140
+ ...(action.requireUpgrade ? { isOverLimit: true } : {}),
141
+ },
142
+ },
143
+ };
144
+ }
145
+ case ACTION_SET_TIER_PLANS_ENABLED: {
146
+ return {
147
+ ...state,
148
+ features: {
149
+ ...state.features,
150
+ aiAssistantFeature: {
151
+ ...state.features.aiAssistantFeature,
152
+ tierPlansEnabled: action.tierPlansEnabled,
153
+ },
154
+ },
155
+ };
156
+ }
157
+ case ACTION_SET_SITE_DETAILS: {
158
+ return {
159
+ ...state,
160
+ siteDetails: action.siteDetails,
161
+ };
162
+ }
163
+ case ACTION_SET_SELECTED_LOGO_INDEX: {
164
+ return {
165
+ ...state,
166
+ selectedLogoIndex: action.selectedLogoIndex,
167
+ };
168
+ }
169
+ case ACTION_ADD_LOGO_TO_HISTORY: {
170
+ const history = [...state.history, action.logo];
171
+ return {
172
+ ...state,
173
+ history,
174
+ selectedLogoIndex: history.length - 1,
175
+ };
176
+ }
177
+ case ACTION_SET_IS_SAVING_LOGO_TO_LIBRARY: {
178
+ return {
179
+ ...state,
180
+ _meta: {
181
+ ...(state._meta ?? {}),
182
+ isSavingLogoToLibrary: action.isSavingLogoToLibrary,
183
+ },
184
+ };
185
+ }
186
+ case ACTION_SET_IS_APPLYING_LOGO: {
187
+ return {
188
+ ...state,
189
+ _meta: {
190
+ ...(state._meta ?? {}),
191
+ isApplyingLogo: action.isApplyingLogo,
192
+ },
193
+ };
194
+ }
195
+ case ACTION_SAVE_SELECTED_LOGO: {
196
+ const selectedLogo = state.history?.[state.selectedLogoIndex];
197
+ return {
198
+ ...state,
199
+ history: [
200
+ ...state.history.slice(0, state.selectedLogoIndex),
201
+ {
202
+ ...selectedLogo,
203
+ mediaId: action.mediaId,
204
+ url: action.url,
205
+ },
206
+ ...state.history.slice(state.selectedLogoIndex + 1),
207
+ ],
208
+ };
209
+ }
210
+ case ACTION_SET_IS_REQUESTING_IMAGE: {
211
+ return {
212
+ ...state,
213
+ _meta: {
214
+ ...(state._meta ?? {}),
215
+ isRequestingImage: action.isRequestingImage,
216
+ },
217
+ };
218
+ }
219
+ case ACTION_SET_IS_ENHANCING_PROMPT: {
220
+ return {
221
+ ...state,
222
+ _meta: {
223
+ ...(state._meta ?? {}),
224
+ isEnhancingPrompt: action.isEnhancingPrompt,
225
+ },
226
+ };
227
+ }
228
+ case ACTION_SET_SITE_HISTORY: {
229
+ return {
230
+ ...state,
231
+ history: action.history,
232
+ selectedLogoIndex: action.history?.length ? action.history.length - 1 : 0,
233
+ };
234
+ }
235
+ case ACTION_SET_FEATURE_FETCH_ERROR:
236
+ return {
237
+ ...state,
238
+ _meta: {
239
+ ...(state._meta ?? {}),
240
+ featureFetchError: action.error,
241
+ },
242
+ };
243
+ case ACTION_SET_FIRST_LOGO_PROMPT_FETCH_ERROR:
244
+ return {
245
+ ...state,
246
+ _meta: {
247
+ ...(state._meta ?? {}),
248
+ firstLogoPromptFetchError: action.error,
249
+ },
250
+ };
251
+ case ACTION_SET_ENHANCE_PROMPT_FETCH_ERROR:
252
+ return {
253
+ ...state,
254
+ _meta: {
255
+ ...(state._meta ?? {}),
256
+ enhancePromptFetchError: action.error,
257
+ },
258
+ };
259
+ case ACTION_SET_LOGO_FETCH_ERROR:
260
+ return {
261
+ ...state,
262
+ _meta: {
263
+ ...(state._meta ?? {}),
264
+ logoFetchError: action.error,
265
+ },
266
+ };
267
+ case ACTION_SET_SAVE_TO_LIBRARY_ERROR:
268
+ return {
269
+ ...state,
270
+ _meta: {
271
+ ...(state._meta ?? {}),
272
+ saveToLibraryError: action.error,
273
+ },
274
+ };
275
+ case ACTION_SET_LOGO_UPDATE_ERROR:
276
+ return {
277
+ ...state,
278
+ _meta: {
279
+ ...(state._meta ?? {}),
280
+ logoUpdateError: action.error,
281
+ },
282
+ };
283
+ case ACTION_SET_CONTEXT:
284
+ return {
285
+ ...state,
286
+ _meta: {
287
+ ...(state._meta ?? {}),
288
+ context: action.context,
289
+ },
290
+ };
291
+ }
292
+ return state;
293
+ }