@spfn/cms 0.1.0-alpha.6 → 0.1.0-alpha.60

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 (176) hide show
  1. package/dist/actions.d.ts +140 -6
  2. package/dist/actions.js +97 -10
  3. package/dist/actions.js.map +1 -1
  4. package/dist/client.d.ts +43 -9
  5. package/dist/client.js +406 -56
  6. package/dist/client.js.map +1 -1
  7. package/dist/contracts/labels.d.ts +149 -0
  8. package/dist/contracts/labels.js +166 -0
  9. package/dist/contracts/labels.js.map +1 -0
  10. package/dist/contracts/published-cache.d.ts +25 -0
  11. package/dist/contracts/published-cache.js +32 -0
  12. package/dist/contracts/published-cache.js.map +1 -0
  13. package/dist/contracts/values.d.ts +69 -0
  14. package/dist/contracts/values.js +100 -0
  15. package/dist/contracts/values.js.map +1 -0
  16. package/dist/entities/cms-audit-logs.d.ts +15 -70
  17. package/dist/entities/cms-audit-logs.js +75 -100
  18. package/dist/entities/cms-audit-logs.js.map +1 -1
  19. package/dist/entities/cms-draft-cache.d.ts +13 -73
  20. package/dist/entities/cms-draft-cache.js +35 -109
  21. package/dist/entities/cms-draft-cache.js.map +1 -1
  22. package/dist/entities/cms-label-values.d.ts +14 -65
  23. package/dist/entities/cms-label-values.js +78 -102
  24. package/dist/entities/cms-label-values.js.map +1 -1
  25. package/dist/entities/cms-label-versions.d.ts +16 -49
  26. package/dist/entities/cms-label-versions.js +73 -77
  27. package/dist/entities/cms-label-versions.js.map +1 -1
  28. package/dist/entities/cms-labels.d.ts +17 -14
  29. package/dist/entities/cms-labels.js +39 -45
  30. package/dist/entities/cms-labels.js.map +1 -1
  31. package/dist/entities/cms-published-cache.d.ts +14 -69
  32. package/dist/entities/cms-published-cache.js +33 -100
  33. package/dist/entities/cms-published-cache.js.map +1 -1
  34. package/dist/entities/index.d.ts +7 -10
  35. package/dist/entities/index.js +217 -9
  36. package/dist/entities/index.js.map +1 -1
  37. package/dist/generators/index.d.ts +8 -7
  38. package/dist/generators/index.js +657 -17
  39. package/dist/generators/index.js.map +1 -1
  40. package/dist/index.d.ts +134 -20
  41. package/dist/index.js +1115 -23
  42. package/dist/index.js.map +1 -1
  43. package/dist/{generators/label-sync-generator.d.ts → label-sync-generator-lQrcVfja.d.ts} +9 -6
  44. package/dist/labels/index.d.ts +31 -4
  45. package/dist/labels/index.js +31 -6
  46. package/dist/labels/index.js.map +1 -1
  47. package/dist/repositories/index.d.ts +205 -6
  48. package/dist/repositories/index.js +435 -8
  49. package/dist/repositories/index.js.map +1 -1
  50. package/dist/routes/labels/[id]/index.js +499 -89
  51. package/dist/routes/labels/[id]/index.js.map +1 -1
  52. package/dist/routes/labels/{[id] → _id_}/index.d.ts +5 -3
  53. package/dist/routes/labels/by-key/[key]/index.js +453 -29
  54. package/dist/routes/labels/by-key/[key]/index.js.map +1 -1
  55. package/dist/routes/labels/by-key/_key_/index.d.ts +10 -0
  56. package/dist/routes/labels/index.d.ts +5 -3
  57. package/dist/routes/labels/index.js +488 -68
  58. package/dist/routes/labels/index.js.map +1 -1
  59. package/dist/routes/published-cache/index.d.ts +5 -3
  60. package/dist/routes/published-cache/index.js +325 -30
  61. package/dist/routes/published-cache/index.js.map +1 -1
  62. package/dist/routes/values/[labelId]/[version]/index.js +467 -41
  63. package/dist/routes/values/[labelId]/[version]/index.js.map +1 -1
  64. package/dist/routes/values/[labelId]/index.js +463 -39
  65. package/dist/routes/values/[labelId]/index.js.map +1 -1
  66. package/dist/routes/values/_labelId_/_version_/index.d.ts +10 -0
  67. package/dist/routes/values/_labelId_/index.d.ts +10 -0
  68. package/dist/server.d.ts +17 -7
  69. package/dist/server.js +263 -252
  70. package/dist/server.js.map +1 -1
  71. package/dist/store.d.ts +8 -14
  72. package/dist/store.js +396 -198
  73. package/dist/store.js.map +1 -1
  74. package/dist/types.d.ts +14 -7
  75. package/dist/types.js +0 -6
  76. package/dist/types.js.map +1 -1
  77. package/migrations/0000_condemned_centennial.sql +89 -0
  78. package/migrations/meta/0000_snapshot.json +687 -0
  79. package/migrations/meta/_journal.json +13 -0
  80. package/package.json +33 -16
  81. package/dist/actions.d.ts.map +0 -1
  82. package/dist/client.d.ts.map +0 -1
  83. package/dist/cms.config.d.ts +0 -77
  84. package/dist/cms.config.d.ts.map +0 -1
  85. package/dist/cms.config.js +0 -111
  86. package/dist/cms.config.js.map +0 -1
  87. package/dist/entities/cms-audit-logs.d.ts.map +0 -1
  88. package/dist/entities/cms-draft-cache.d.ts.map +0 -1
  89. package/dist/entities/cms-label-values.d.ts.map +0 -1
  90. package/dist/entities/cms-label-versions.d.ts.map +0 -1
  91. package/dist/entities/cms-labels.d.ts.map +0 -1
  92. package/dist/entities/cms-published-cache.d.ts.map +0 -1
  93. package/dist/entities/index.d.ts.map +0 -1
  94. package/dist/generators/index.d.ts.map +0 -1
  95. package/dist/generators/label-sync-generator.d.ts.map +0 -1
  96. package/dist/generators/label-sync-generator.js +0 -87
  97. package/dist/generators/label-sync-generator.js.map +0 -1
  98. package/dist/helpers/locale.actions.d.ts +0 -132
  99. package/dist/helpers/locale.actions.d.ts.map +0 -1
  100. package/dist/helpers/locale.actions.js +0 -210
  101. package/dist/helpers/locale.actions.js.map +0 -1
  102. package/dist/helpers/locale.constants.d.ts +0 -10
  103. package/dist/helpers/locale.constants.d.ts.map +0 -1
  104. package/dist/helpers/locale.constants.js +0 -10
  105. package/dist/helpers/locale.constants.js.map +0 -1
  106. package/dist/helpers/locale.d.ts +0 -17
  107. package/dist/helpers/locale.d.ts.map +0 -1
  108. package/dist/helpers/locale.js +0 -20
  109. package/dist/helpers/locale.js.map +0 -1
  110. package/dist/helpers/sync.d.ts +0 -41
  111. package/dist/helpers/sync.d.ts.map +0 -1
  112. package/dist/helpers/sync.js +0 -309
  113. package/dist/helpers/sync.js.map +0 -1
  114. package/dist/index.d.ts.map +0 -1
  115. package/dist/init.d.ts +0 -31
  116. package/dist/init.d.ts.map +0 -1
  117. package/dist/init.js +0 -36
  118. package/dist/init.js.map +0 -1
  119. package/dist/labels/helpers.d.ts +0 -31
  120. package/dist/labels/helpers.d.ts.map +0 -1
  121. package/dist/labels/helpers.js +0 -60
  122. package/dist/labels/helpers.js.map +0 -1
  123. package/dist/labels/index.d.ts.map +0 -1
  124. package/dist/repositories/cms-draft-cache.repository.d.ts +0 -62
  125. package/dist/repositories/cms-draft-cache.repository.d.ts.map +0 -1
  126. package/dist/repositories/cms-draft-cache.repository.js +0 -56
  127. package/dist/repositories/cms-draft-cache.repository.js.map +0 -1
  128. package/dist/repositories/cms-label-values.repository.d.ts +0 -32
  129. package/dist/repositories/cms-label-values.repository.d.ts.map +0 -1
  130. package/dist/repositories/cms-label-values.repository.js +0 -72
  131. package/dist/repositories/cms-label-values.repository.js.map +0 -1
  132. package/dist/repositories/cms-labels.repository.d.ts +0 -53
  133. package/dist/repositories/cms-labels.repository.d.ts.map +0 -1
  134. package/dist/repositories/cms-labels.repository.js +0 -77
  135. package/dist/repositories/cms-labels.repository.js.map +0 -1
  136. package/dist/repositories/cms-published-cache.repository.d.ts +0 -53
  137. package/dist/repositories/cms-published-cache.repository.d.ts.map +0 -1
  138. package/dist/repositories/cms-published-cache.repository.js +0 -54
  139. package/dist/repositories/cms-published-cache.repository.js.map +0 -1
  140. package/dist/repositories/index.d.ts.map +0 -1
  141. package/dist/routes/labels/[id]/contract.d.ts +0 -68
  142. package/dist/routes/labels/[id]/contract.d.ts.map +0 -1
  143. package/dist/routes/labels/[id]/contract.js +0 -84
  144. package/dist/routes/labels/[id]/contract.js.map +0 -1
  145. package/dist/routes/labels/[id]/index.d.ts.map +0 -1
  146. package/dist/routes/labels/by-key/[key]/contract.d.ts +0 -24
  147. package/dist/routes/labels/by-key/[key]/contract.d.ts.map +0 -1
  148. package/dist/routes/labels/by-key/[key]/contract.js +0 -28
  149. package/dist/routes/labels/by-key/[key]/contract.js.map +0 -1
  150. package/dist/routes/labels/by-key/[key]/index.d.ts +0 -8
  151. package/dist/routes/labels/by-key/[key]/index.d.ts.map +0 -1
  152. package/dist/routes/labels/contract.d.ts +0 -59
  153. package/dist/routes/labels/contract.d.ts.map +0 -1
  154. package/dist/routes/labels/contract.js +0 -75
  155. package/dist/routes/labels/contract.js.map +0 -1
  156. package/dist/routes/labels/index.d.ts.map +0 -1
  157. package/dist/routes/published-cache/contract.d.ts +0 -25
  158. package/dist/routes/published-cache/contract.d.ts.map +0 -1
  159. package/dist/routes/published-cache/contract.js +0 -35
  160. package/dist/routes/published-cache/contract.js.map +0 -1
  161. package/dist/routes/published-cache/index.d.ts.map +0 -1
  162. package/dist/routes/values/[labelId]/[version]/contract.d.ts +0 -29
  163. package/dist/routes/values/[labelId]/[version]/contract.d.ts.map +0 -1
  164. package/dist/routes/values/[labelId]/[version]/contract.js +0 -33
  165. package/dist/routes/values/[labelId]/[version]/contract.js.map +0 -1
  166. package/dist/routes/values/[labelId]/[version]/index.d.ts +0 -8
  167. package/dist/routes/values/[labelId]/[version]/index.d.ts.map +0 -1
  168. package/dist/routes/values/[labelId]/contract.d.ts +0 -38
  169. package/dist/routes/values/[labelId]/contract.d.ts.map +0 -1
  170. package/dist/routes/values/[labelId]/contract.js +0 -59
  171. package/dist/routes/values/[labelId]/contract.js.map +0 -1
  172. package/dist/routes/values/[labelId]/index.d.ts +0 -8
  173. package/dist/routes/values/[labelId]/index.d.ts.map +0 -1
  174. package/dist/server.d.ts.map +0 -1
  175. package/dist/store.d.ts.map +0 -1
  176. package/dist/types.d.ts.map +0 -1
package/dist/store.js CHANGED
@@ -1,205 +1,403 @@
1
- /**
2
- * CMS Zustand Store
3
- *
4
- * 클라이언트 컴포넌트에서 CMS 사용을 위한 상태 관리
5
- * - 서버에서 초기화된 데이터를 클라이언트로 전달
6
- * - 클라이언트에서 비동기로 로드 가능
7
- * - 서버 API와 동일한 패턴 ({ t } 사용)
8
- */
9
- 'use client';
10
- import React from 'react';
11
- import { create } from 'zustand';
12
- import { cmsApi } from './client';
13
- /**
14
- * 변수 치환 헬퍼 (서버와 동일)
15
- */
1
+ "use client";
2
+
3
+ // src/store.ts
4
+ import React from "react";
5
+ import { create } from "zustand";
6
+
7
+ // src/client.ts
8
+ import { client } from "@spfn/core/client";
9
+
10
+ // src/contracts/labels.ts
11
+ import { Type } from "@sinclair/typebox";
12
+ var getLabelsContract = {
13
+ method: "GET",
14
+ path: "/cms/labels",
15
+ query: Type.Object({
16
+ section: Type.Optional(Type.String({ description: "\uC139\uC158\uC73C\uB85C \uD544\uD130\uB9C1 (\uC608: home, why-futureplay)" })),
17
+ limit: Type.Optional(Type.Number({ minimum: 1, maximum: 100, default: 20, description: "\uD398\uC774\uC9C0\uB2F9 \uD56D\uBAA9 \uC218" })),
18
+ offset: Type.Optional(Type.Number({ minimum: 0, default: 0, description: "\uC2DC\uC791 \uC624\uD504\uC14B" }))
19
+ }),
20
+ response: Type.Object({
21
+ labels: Type.Array(Type.Object({
22
+ id: Type.Number(),
23
+ key: Type.String(),
24
+ section: Type.String(),
25
+ type: Type.String(),
26
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
27
+ createdBy: Type.Union([Type.String(), Type.Null()]),
28
+ createdAt: Type.String(),
29
+ updatedAt: Type.String()
30
+ })),
31
+ total: Type.Number(),
32
+ limit: Type.Number(),
33
+ offset: Type.Number()
34
+ })
35
+ };
36
+ var createLabelContract = {
37
+ method: "POST",
38
+ path: "/cms/labels",
39
+ body: Type.Object({
40
+ key: Type.String({
41
+ description: "\uACE0\uC720 \uD0A4 (\uC608: home.hero.title)",
42
+ pattern: "^[a-z0-9-]+\\.[a-z0-9-]+\\.[a-z0-9-]+$"
43
+ }),
44
+ section: Type.String({
45
+ description: "\uC139\uC158 \uC774\uB984 (\uC608: home, why-futureplay)",
46
+ pattern: "^[a-z0-9-]+$"
47
+ }),
48
+ type: Type.Union([
49
+ Type.Literal("text"),
50
+ Type.Literal("image"),
51
+ Type.Literal("video"),
52
+ Type.Literal("file"),
53
+ Type.Literal("object")
54
+ ], { description: "\uAC12 \uD0C0\uC785" }),
55
+ createdBy: Type.Optional(Type.String({ description: "\uC0DD\uC131\uC790 ID" }))
56
+ }),
57
+ response: Type.Union([
58
+ Type.Object({
59
+ id: Type.Number(),
60
+ key: Type.String(),
61
+ section: Type.String(),
62
+ type: Type.String(),
63
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
64
+ createdBy: Type.Union([Type.String(), Type.Null()]),
65
+ createdAt: Type.String(),
66
+ updatedAt: Type.String()
67
+ }),
68
+ Type.Object({
69
+ error: Type.String(),
70
+ key: Type.Optional(Type.String())
71
+ })
72
+ ])
73
+ };
74
+ var getLabelContract = {
75
+ method: "GET",
76
+ path: "/cms/labels/:id",
77
+ params: Type.Object({
78
+ id: Type.String({ description: "\uB77C\uBCA8 ID" })
79
+ }),
80
+ response: Type.Union([
81
+ Type.Object({
82
+ id: Type.Number(),
83
+ key: Type.String(),
84
+ section: Type.String(),
85
+ type: Type.String(),
86
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
87
+ createdBy: Type.Union([Type.String(), Type.Null()]),
88
+ createdAt: Type.String(),
89
+ updatedAt: Type.String()
90
+ }),
91
+ Type.Object({
92
+ error: Type.String()
93
+ })
94
+ ])
95
+ };
96
+ var updateLabelContract = {
97
+ method: "PATCH",
98
+ path: "/cms/labels/:id",
99
+ params: Type.Object({
100
+ id: Type.String({ description: "\uB77C\uBCA8 ID" })
101
+ }),
102
+ body: Type.Object({
103
+ section: Type.Optional(Type.String({ description: "\uC139\uC158 \uBCC0\uACBD" })),
104
+ type: Type.Optional(Type.Union([
105
+ Type.Literal("text"),
106
+ Type.Literal("image"),
107
+ Type.Literal("video"),
108
+ Type.Literal("file"),
109
+ Type.Literal("object")
110
+ ]))
111
+ }),
112
+ response: Type.Union([
113
+ Type.Object({
114
+ id: Type.Number(),
115
+ key: Type.String(),
116
+ section: Type.String(),
117
+ type: Type.String(),
118
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
119
+ createdBy: Type.Union([Type.String(), Type.Null()]),
120
+ createdAt: Type.String(),
121
+ updatedAt: Type.String()
122
+ }),
123
+ Type.Object({
124
+ error: Type.String()
125
+ })
126
+ ])
127
+ };
128
+ var deleteLabelContract = {
129
+ method: "DELETE",
130
+ path: "/cms/labels/:id",
131
+ params: Type.Object({
132
+ id: Type.String({ description: "\uB77C\uBCA8 ID" })
133
+ }),
134
+ response: Type.Union([
135
+ Type.Object({
136
+ success: Type.Boolean(),
137
+ id: Type.Number()
138
+ }),
139
+ Type.Object({
140
+ error: Type.String()
141
+ })
142
+ ])
143
+ };
144
+ var getLabelByKeyContract = {
145
+ method: "GET",
146
+ path: "/cms/labels/by-key/:key",
147
+ params: Type.Object({
148
+ key: Type.String({ description: "\uB77C\uBCA8 Key (\uC608: home.hero.title)" })
149
+ }),
150
+ response: Type.Union([
151
+ Type.Object({
152
+ id: Type.Number(),
153
+ key: Type.String(),
154
+ section: Type.String(),
155
+ type: Type.String(),
156
+ publishedVersion: Type.Union([Type.Number(), Type.Null()]),
157
+ createdBy: Type.Union([Type.String(), Type.Null()]),
158
+ createdAt: Type.String(),
159
+ updatedAt: Type.String()
160
+ }),
161
+ Type.Object({
162
+ error: Type.String(),
163
+ key: Type.Optional(Type.String())
164
+ })
165
+ ])
166
+ };
167
+
168
+ // src/contracts/published-cache.ts
169
+ import { Type as Type2 } from "@sinclair/typebox";
170
+ var SectionData = Type2.Object({
171
+ section: Type2.String(),
172
+ locale: Type2.String(),
173
+ content: Type2.Record(Type2.String(), Type2.Any()),
174
+ version: Type2.Number(),
175
+ publishedAt: Type2.Union([Type2.String(), Type2.Null()])
176
+ });
177
+ var getPublishedCacheContract = {
178
+ method: "GET",
179
+ path: "/cms/published-cache",
180
+ query: Type2.Object({
181
+ sections: Type2.Union([
182
+ Type2.String({ description: "\uB2E8\uC77C \uC139\uC158 \uC774\uB984 (\uC608: home)" }),
183
+ Type2.Array(Type2.String(), { description: '\uC5EC\uB7EC \uC139\uC158 \uC774\uB984 (\uC608: ["home", "footer"])' })
184
+ ]),
185
+ locale: Type2.Optional(Type2.String({ default: "ko", description: "\uC5B8\uC5B4 \uCF54\uB4DC" }))
186
+ }),
187
+ response: Type2.Union([
188
+ // 성공: 항상 배열로 반환
189
+ Type2.Array(SectionData),
190
+ // 에러
191
+ Type2.Object({
192
+ error: Type2.String()
193
+ })
194
+ ])
195
+ };
196
+
197
+ // src/init.tsx
198
+ import { useEffect } from "react";
199
+
200
+ // src/client.ts
201
+ var cmsApi = {
202
+ /**
203
+ * Labels API
204
+ */
205
+ labels: {
206
+ /**
207
+ * GET /cms/labels
208
+ * 라벨 목록 조회 (섹션 필터, 페이지네이션)
209
+ */
210
+ list: (options) => client.call(getLabelsContract, options),
211
+ /**
212
+ * GET /cms/labels/:id
213
+ * 특정 라벨 조회
214
+ */
215
+ getById: (options) => client.call(getLabelContract, options),
216
+ /**
217
+ * POST /cms/labels
218
+ * 새 라벨 생성
219
+ */
220
+ create: (options) => client.call(createLabelContract, options),
221
+ /**
222
+ * PATCH /cms/labels/:id
223
+ * 라벨 업데이트
224
+ */
225
+ update: (options) => client.call(updateLabelContract, options),
226
+ /**
227
+ * DELETE /cms/labels/:id
228
+ * 라벨 삭제
229
+ */
230
+ delete: (options) => client.call(deleteLabelContract, options)
231
+ },
232
+ /**
233
+ * Published Cache API
234
+ */
235
+ publishedCache: {
236
+ /**
237
+ * GET /cms/published-cache
238
+ * 발행된 콘텐츠 캐시 조회
239
+ */
240
+ get: (options) => client.call(getPublishedCacheContract, options)
241
+ }
242
+ };
243
+
244
+ // src/store.ts
16
245
  function replaceVariables(text, replace) {
17
- return text.replace(/\{(\w+)}/g, (match, key) => {
18
- const value = replace[key];
19
- return value !== undefined ? String(value) : match;
20
- });
246
+ return text.replace(/\{(\w+)}/g, (match, key) => {
247
+ const value = replace[key];
248
+ return value !== void 0 ? String(value) : match;
249
+ });
21
250
  }
22
- export const useCmsStore = create((set, get) => ({
23
- sections: {},
24
- loading: {},
25
- setSection: (section, data) => {
26
- set((state) => ({
27
- sections: {
28
- ...state.sections,
29
- [section]: data,
30
- },
31
- }));
32
- },
33
- setSections: (sections) => {
34
- set((state) => ({
35
- sections: {
36
- ...state.sections,
37
- ...sections,
38
- },
39
- }));
40
- },
41
- loadSection: async (section, locale = 'ko') => {
42
- const state = get();
43
- // 이미 로드 중이면 스킵
44
- if (state.loading[section]) {
45
- return;
46
- }
47
- // 이미 로드되어 있으면 스킵
48
- if (state.sections[section]) {
49
- return;
50
- }
51
- set((state) => ({
52
- loading: { ...state.loading, [section]: true },
53
- }));
54
- try {
55
- const response = await cmsApi.publishedCache.get({
56
- query: { sections: section, locale },
57
- });
58
- // Check for error response
59
- if ('error' in response) {
60
- console.error(`Failed to load section ${section}:`, response.error);
61
- return;
62
- }
63
- // Response is array, get first element
64
- const data = response[0];
65
- if (!data) {
66
- console.warn(`Section ${section} not found`);
67
- return;
68
- }
69
- const sectionData = {
70
- section: data.section,
71
- locale: data.locale,
72
- content: data.content || {},
73
- version: data.version || 0,
74
- publishedAt: data.publishedAt || null,
75
- };
76
- set((state) => ({
77
- sections: {
78
- ...state.sections,
79
- [section]: sectionData,
80
- },
81
- loading: { ...state.loading, [section]: false },
82
- }));
251
+ var useCmsStore = create((set, get) => ({
252
+ sections: {},
253
+ loading: {},
254
+ setSection: (section, data) => {
255
+ set((state) => ({
256
+ sections: {
257
+ ...state.sections,
258
+ [section]: data
259
+ }
260
+ }));
261
+ },
262
+ setSections: (sections) => {
263
+ set((state) => ({
264
+ sections: {
265
+ ...state.sections,
266
+ ...sections
267
+ }
268
+ }));
269
+ },
270
+ loadSection: async (section, locale = "ko") => {
271
+ const state = get();
272
+ if (state.loading[section]) {
273
+ return;
274
+ }
275
+ if (state.sections[section]) {
276
+ return;
277
+ }
278
+ set((state2) => ({
279
+ loading: { ...state2.loading, [section]: true }
280
+ }));
281
+ try {
282
+ const response = await cmsApi.publishedCache.get({
283
+ query: { sections: section, locale }
284
+ });
285
+ if ("error" in response) {
286
+ console.error(`Failed to load section ${section}:`, response.error);
287
+ return;
288
+ }
289
+ const data = response[0];
290
+ if (!data) {
291
+ console.warn(`Section ${section} not found`);
292
+ return;
293
+ }
294
+ const sectionData = {
295
+ section: data.section,
296
+ locale: data.locale,
297
+ content: data.content || {},
298
+ version: data.version || 0,
299
+ publishedAt: data.publishedAt || null
300
+ };
301
+ set((state2) => ({
302
+ sections: {
303
+ ...state2.sections,
304
+ [section]: sectionData
305
+ },
306
+ loading: { ...state2.loading, [section]: false }
307
+ }));
308
+ } catch (error) {
309
+ console.error(`Error loading CMS section ${section}:`, error);
310
+ set((state2) => ({
311
+ loading: { ...state2.loading, [section]: false }
312
+ }));
313
+ }
314
+ },
315
+ updateLabel: (section, key, value) => {
316
+ set((state) => ({
317
+ sections: {
318
+ ...state.sections,
319
+ [section]: {
320
+ ...state.sections[section],
321
+ content: {
322
+ ...state.sections[section]?.content,
323
+ [`${section}.${key}`]: value
324
+ }
83
325
  }
84
- catch (error) {
85
- console.error(`Error loading CMS section ${section}:`, error);
86
- set((state) => ({
87
- loading: { ...state.loading, [section]: false },
88
- }));
89
- }
90
- },
91
- updateLabel: (section, key, value) => {
92
- set((state) => ({
93
- sections: {
94
- ...state.sections,
95
- [section]: {
96
- ...state.sections[section],
97
- content: {
98
- ...state.sections[section]?.content,
99
- [`${section}.${key}`]: value,
100
- },
101
- },
102
- },
103
- }));
104
- },
105
- reset: () => {
106
- set({
107
- sections: {},
108
- loading: {},
109
- });
110
- },
326
+ }
327
+ }));
328
+ },
329
+ reset: () => {
330
+ set({
331
+ sections: {},
332
+ loading: {}
333
+ });
334
+ }
111
335
  }));
112
- /**
113
- * 섹션 Hook (서버 API와 동일한 패턴)
114
- *
115
- * @param section - 섹션 이름
116
- * @param options - 옵션 (autoLoad: 자동 로드 여부)
117
- * @returns { t, data, loading }
118
- *
119
- * @example
120
- * ```tsx
121
- * 'use client';
122
- * import { useSection } from '@/lib/cms';
123
- *
124
- * export function ClientComponent()
125
- * {
126
- * const { t } = useSection('home');
127
- * return <h1>{t('hero.title')}</h1>;
128
- * }
129
- * ```
130
- */
131
- export function useSection(section, options = {}) {
132
- const { autoLoad = false, locale = 'ko' } = options;
133
- const sectionData = useCmsStore((state) => state.sections[section]);
134
- const loading = useCmsStore((state) => state.loading[section] ?? false);
135
- const loadSection = useCmsStore((state) => state.loadSection);
136
- // 자동 로드 옵션이 켜져있고 데이터가 없으면 로드
137
- React.useEffect(() => {
138
- if (autoLoad && !sectionData && !loading) {
139
- loadSection(section, locale);
140
- }
141
- }, [autoLoad, section, locale, sectionData, loading, loadSection]);
142
- // Translation function (서버와 동일)
143
- const t = React.useCallback((key, defaultValue, replace) => {
144
- if (!sectionData) {
145
- return defaultValue;
146
- }
147
- const fullKey = `${section}.${key}`;
148
- let value = sectionData.content[fullKey];
149
- if (value === undefined) {
150
- value = defaultValue;
151
- }
152
- // 문자열이고 치환 맵이 있으면 변수 치환
153
- if (typeof value === 'string' && replace) {
154
- value = replaceVariables(value, replace);
155
- }
156
- return value;
157
- }, [section, sectionData]);
158
- return {
159
- t,
160
- data: sectionData,
161
- loading,
162
- };
336
+ function useSection(section, options = {}) {
337
+ const { autoLoad = false, locale = "ko" } = options;
338
+ const sectionData = useCmsStore((state) => state.sections[section]);
339
+ const loading = useCmsStore((state) => state.loading[section] ?? false);
340
+ const loadSection = useCmsStore((state) => state.loadSection);
341
+ React.useEffect(() => {
342
+ if (autoLoad && !sectionData && !loading) {
343
+ loadSection(section, locale);
344
+ }
345
+ }, [autoLoad, section, locale, sectionData, loading, loadSection]);
346
+ const t = React.useCallback(
347
+ (key, defaultValue, replace) => {
348
+ if (!sectionData) {
349
+ return defaultValue;
350
+ }
351
+ const fullKey = `${section}.${key}`;
352
+ let value = sectionData.content[fullKey];
353
+ if (value === void 0) {
354
+ value = defaultValue;
355
+ }
356
+ if (typeof value === "string" && replace) {
357
+ value = replaceVariables(value, replace);
358
+ }
359
+ return value;
360
+ },
361
+ [section, sectionData]
362
+ );
363
+ return {
364
+ t,
365
+ data: sectionData,
366
+ loading
367
+ };
163
368
  }
164
- /**
165
- * 여러 섹션 Hook
166
- *
167
- * @param sectionNames - 섹션 이름 배열
168
- * @returns { [section]: { t, data, loading }, ... }
169
- *
170
- * @example
171
- * ```tsx
172
- * const sections = useSections(['home', 'why-futureplay']);
173
- * sections.home.t('hero.title');
174
- * ```
175
- */
176
- export function useSections(sectionNames) {
177
- const allSections = useCmsStore((state) => state.sections);
178
- const allLoading = useCmsStore((state) => state.loading);
179
- const result = {};
180
- sectionNames.forEach((section) => {
181
- const sectionData = allSections[section];
182
- const loading = allLoading[section] ?? false;
183
- const t = (key, defaultValue, replace) => {
184
- if (!sectionData) {
185
- return defaultValue;
186
- }
187
- const fullKey = `${section}.${key}`;
188
- let value = sectionData.content[fullKey];
189
- if (value === undefined) {
190
- value = defaultValue;
191
- }
192
- if (typeof value === 'string' && replace) {
193
- value = replaceVariables(value, replace);
194
- }
195
- return value;
196
- };
197
- result[section] = {
198
- t,
199
- data: sectionData,
200
- loading,
201
- };
202
- });
203
- return result;
369
+ function useSections(sectionNames) {
370
+ const allSections = useCmsStore((state) => state.sections);
371
+ const allLoading = useCmsStore((state) => state.loading);
372
+ const result = {};
373
+ sectionNames.forEach((section) => {
374
+ const sectionData = allSections[section];
375
+ const loading = allLoading[section] ?? false;
376
+ const t = (key, defaultValue, replace) => {
377
+ if (!sectionData) {
378
+ return defaultValue;
379
+ }
380
+ const fullKey = `${section}.${key}`;
381
+ let value = sectionData.content[fullKey];
382
+ if (value === void 0) {
383
+ value = defaultValue;
384
+ }
385
+ if (typeof value === "string" && replace) {
386
+ value = replaceVariables(value, replace);
387
+ }
388
+ return value;
389
+ };
390
+ result[section] = {
391
+ t,
392
+ data: sectionData,
393
+ loading
394
+ };
395
+ });
396
+ return result;
204
397
  }
398
+ export {
399
+ useCmsStore,
400
+ useSection,
401
+ useSections
402
+ };
205
403
  //# sourceMappingURL=store.js.map