PluginProbe
The Innovative Form Builder – IvyForms / 1.1
The Innovative Form Builder – IvyForms v1.1
1.5.1 1.5 1.4.1 1.4 trunk 0.1.2 0.2 0.2.1 0.3 0.3.1 0.4 0.5 0.6 0.6.1 0.6.1-backup 0.6.1.1 0.7 0.8 0.8.1 0.8.2 0.9 0.9.1 1.0 1.1 1.1.1 All 27 releases
ivyforms / frontend / src / stores / useTemplateStore.ts

useTemplateStore.ts in The Innovative Form Builder – IvyForms 1.1, at frontend/src/stores/useTemplateStore.ts

200 lines 4.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { defineStore } from 'pinia'
2 import { ref } from 'vue'
3 import { useLabels } from '@/composables/useLabels'
4 import IvyMessage from '@/views/_components/message/ivyMessage.ts'
5 import { useApiClient } from '@/composables/useApiClient.ts'
6
7 interface FieldData {
8 id: string
9 type: string
10 label: string
11 placeholder?: string
12 required: boolean
13 validation?: Record<string, unknown>
14 settings?: Record<string, unknown>
15 }
16
17 interface FormSettings {
18 success_message?: string
19 [key: string]: unknown
20 }
21
22 interface IntegrationSettings {
23 wpdatatables: {
24 enabled: boolean
25 }
26 [key: string]: unknown
27 }
28
29 interface FormData {
30 name: string
31 description: string
32 status: string
33 published?: boolean
34 showTitle?: boolean
35 showDescription?: boolean
36 storeEntries?: boolean
37 integrationSettings?: IntegrationSettings
38 fields: FieldData[]
39 settings: FormSettings
40 }
41
42 interface TemplateMeta {
43 id: string
44 name: string
45 description: string
46 category: string
47 subcategory?: string
48 is_pro: boolean
49 screenshot: string
50 }
51
52 interface Template extends TemplateMeta {
53 form_data: FormData
54 }
55
56 interface TemplateCategory {
57 name: string
58 description: string
59 }
60
61 export const useTemplateStore = defineStore('ivyformsTemplate', () => {
62 // State
63 const templates = ref<TemplateMeta[]>([])
64 const categories = ref<Record<string, TemplateCategory>>({})
65 const isLoading = ref(false)
66 const error = ref<string | null>(null)
67
68 // Composables
69 const { getLabel } = useLabels()
70 const { request } = useApiClient()
71
72 // Actions
73 const fetchTemplates = async (): Promise<void> => {
74 isLoading.value = true
75 error.value = null
76
77 try {
78 const { data, error: apiError } = await request('templates', {
79 method: 'GET',
80 })
81
82 if (apiError) {
83 throw new Error(apiError)
84 }
85
86 if (data.data.success) {
87 // Use the associative array from backend, preserve IDs
88 templates.value = Object.values(data.data.data.templates)
89 categories.value = data.data.data.categories
90 } else {
91 throw new Error(getLabel('failed_to_fetch_template'))
92 }
93 } catch (err) {
94 error.value = err instanceof Error ? err.message : getLabel('failed_to_fetch_template')
95 console.error(getLabel('template_fetch_error'), err)
96 IvyMessage({
97 message: `${getLabel('failed_to_fetch_template')} ${error.value}`,
98 type: 'error',
99 })
100 throw err
101 } finally {
102 isLoading.value = false
103 }
104 }
105
106 const getTemplate = async (templateId: string): Promise<Template | null> => {
107 try {
108 const { data, error: apiError } = await request(`template/${templateId}`, {
109 method: 'GET',
110 })
111
112 if (apiError) {
113 throw new Error(apiError)
114 }
115
116 if (data.data.success) {
117 return data.data.data
118 } else {
119 throw new Error(getLabel('failed_to_fetch_template'))
120 }
121 } catch (err) {
122 error.value = err instanceof Error ? err.message : getLabel('failed_to_fetch_template')
123 console.error(getLabel('template_fetch_error'), err)
124 IvyMessage({
125 message: `${getLabel('failed_to_fetch_template')} ${error.value}`,
126 type: 'error',
127 })
128 return null
129 }
130 }
131
132 const getTemplatesByCategory = (categoryId: string): TemplateMeta[] => {
133 return templates.value.filter((template) => template.category === categoryId)
134 }
135
136 const searchTemplates = (query: string): TemplateMeta[] => {
137 if (!query.trim()) {
138 return templates.value
139 }
140
141 const searchTerm = query.toLowerCase()
142 return templates.value.filter(
143 (template) =>
144 template.name.toLowerCase().includes(searchTerm) ||
145 template.description.toLowerCase().includes(searchTerm),
146 )
147 }
148
149 const clearError = (): void => {
150 error.value = null
151 }
152
153 const resetStore = (): void => {
154 templates.value = []
155 categories.value = {}
156 isLoading.value = false
157 error.value = null
158 }
159
160 // Getters
161 const getTemplateById = (id: string): TemplateMeta | undefined => {
162 return templates.value.find((template) => template.id === id)
163 }
164
165 const getAvailableCategories = (): TemplateCategory[] => {
166 return Object.values(categories.value)
167 }
168
169 const getTemplatesCount = (): number => {
170 return templates.value.length
171 }
172
173 const getProTemplatesCount = (): number => {
174 return templates.value.filter((template) => template.is_pro).length
175 }
176
177 const getFreeTemplatesCount = (): number => {
178 return templates.value.filter((template) => !template.is_pro).length
179 }
180
181 return {
182 // State
183 templates,
184 categories,
185 isLoading,
186 error,
187 fetchTemplates,
188 getTemplate,
189 getTemplatesByCategory,
190 searchTemplates,
191 clearError,
192 resetStore,
193 getTemplateById,
194 getAvailableCategories,
195 getTemplatesCount,
196 getProTemplatesCount,
197 getFreeTemplatesCount,
198 }
199 })
200