PluginProbe ʕ •ᴥ•ʔ
Hostinger Reach – AI-Powered Email Marketing for WordPress / 1.7.1
Hostinger Reach – AI-Powered Email Marketing for WordPress v1.7.1
1.7.2 1.7.1 1.7.0 1.6.0 1.5.9 1.5.8 1.5.7 1.5.6 1.5.5 1.5.4 1.5.3 1.5.2 1.5.1 1.5.0 1.4.12 1.4.11 1.4.10 1.4.9 1.4.8 1.4.7 trunk 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6
hostinger-reach / frontend / vue / components / PluginEntriesTable.vue
hostinger-reach / frontend / vue / components Last commit date
Modals 1 month ago skeletons 4 months ago ActionButton.vue 5 months ago ActionButtonsSection.vue 5 months ago Banner.vue 3 months ago FAQ.vue 5 months ago FormItem.vue 2 months ago FormsSection.vue 11 months ago Hero.vue 1 month ago Integrations.vue 4 months ago Pagination.vue 10 months ago PluginEntriesTable.vue 4 months ago PluginEntry.vue 4 months ago PluginExpansion.vue 8 months ago ReachContactsSummary.vue 2 weeks ago SyncStatusLabel.vue 6 months ago Tabs.vue 9 months ago Toggle.vue 10 months ago UsageCard.vue 10 months ago UsageCardsRow.vue 1 year ago UsageCardsSection.vue 1 year ago WooCommerce.vue 2 weeks ago WooCommerceEntriesTable.vue 4 months ago
PluginEntriesTable.vue
394 lines
1 <script setup lang="ts">
2 import { computed } from 'vue';
3
4 import PluginEntry from '@/components/PluginEntry.vue';
5 import PluginEntrySkeleton from '@/components/skeletons/PluginEntrySkeleton.vue';
6 import { PLUGIN_STATUSES, type PluginStatus, WOOCOMMERCE_ID } from '@/data/pluginData';
7 import type { Form, Integration } from '@/types/models';
8 import { translate } from '@/utils/translate';
9
10 interface PluginEntryData {
11 integration: Integration;
12 status: PluginStatus;
13 forms: Form[];
14 }
15
16 interface Props {
17 integrations?: Integration[];
18 isLoading?: boolean;
19 }
20
21 const props = withDefaults(defineProps<Props>(), {
22 integrations: () => [],
23 isLoading: false
24 });
25
26 const emit = defineEmits<{
27 goToPlugin: [id: string];
28 disconnectPlugin: [id: string];
29 toggleFormStatus: [form: Form, status: boolean];
30 viewForm: [form: Form];
31 editForm: [form: Form];
32 addForm: [id: string];
33 }>();
34
35 const SKELETON_COUNT = 3;
36
37 const pluginEntries = computed((): PluginEntryData[] => {
38 if (props.isLoading) return [];
39
40 return props.integrations
41 .filter((integration) => integration.isPluginActive)
42 .map((integration) => {
43 const forms = integration.forms || [];
44
45 return {
46 integration,
47 status: integration.isActive ? PLUGIN_STATUSES.ACTIVE : PLUGIN_STATUSES.INACTIVE,
48 forms
49 } as PluginEntryData;
50 })
51 .filter((pluginEntry) => pluginEntry.status === PLUGIN_STATUSES.ACTIVE);
52 });
53 </script>
54
55 <template>
56 <div class="plugin-entries-table">
57 <div class="plugin-entries-table__container">
58 <div class="plugin-entries-table__header">
59 <div class="plugin-entries-table__header-cell plugin-entries-table__header-cell--plugin">
60 <span class="plugin-entries-table__column-title">
61 {{ translate('hostinger_reach_plugin_entries_table_plugin_header') }}
62 </span>
63 </div>
64 <div class="plugin-entries-table__header-cell plugin-entries-table__header-cell--forms">
65 <span
66 v-tooltip.top="translate('hostinger_reach_plugin_entries_table_syncing_tooltip')"
67 class="plugin-entries-table__column-title plugin-entries-table__column-title--with-tooltip"
68 >
69 {{ translate('hostinger_reach_plugin_entries_table_syncing_header') }}
70 </span>
71 </div>
72 <div class="plugin-entries-table__header-cell plugin-entries-table__header-cell--actions"></div>
73 </div>
74
75 <template v-if="isLoading">
76 <PluginEntrySkeleton v-for="i in SKELETON_COUNT" :key="`skeleton-${i}`" />
77 </template>
78
79 <template v-else>
80 <PluginEntry
81 v-for="(pluginEntry, index) in pluginEntries"
82 :key="pluginEntry.integration.id"
83 :initially-expanded="pluginEntry.integration.id === WOOCOMMERCE_ID"
84 :integration="pluginEntry.integration"
85 :plugin-status="pluginEntry.status"
86 :forms="pluginEntry.forms"
87 :class="{
88 'plugin-entries-table__entry-row--with-spacing':
89 pluginEntries.length > 1 && index !== pluginEntries.length - 1
90 }"
91 @toggle-form-status="(form: Form, status: boolean) => emit('toggleFormStatus', form, status)"
92 @view-form="emit('viewForm', $event)"
93 @edit-form="emit('editForm', $event)"
94 @add-form="emit('addForm', $event)"
95 @go-to-plugin="emit('goToPlugin', $event)"
96 @disconnect-plugin="emit('disconnectPlugin', $event)"
97 />
98 </template>
99 </div>
100 </div>
101 </template>
102
103 <style scoped lang="scss">
104 .plugin-entries-table {
105 width: inherit;
106
107 &__container {
108 background: var(--neutral--0);
109 border-radius: 20px;
110 padding: 24px;
111 border: 1px solid var(--neutral--200);
112 overflow: visible;
113 }
114
115 &__header {
116 display: flex;
117 }
118
119 &__header-cell {
120 padding: 12px 0px;
121
122 &--plugin {
123 width: 38%;
124 order: 1;
125 }
126
127 &--forms {
128 width: 20%;
129 order: 2;
130 }
131
132 &--status {
133 width: 20%;
134 order: 3;
135 }
136
137 &--actions {
138 width: 20%;
139 order: 4;
140 }
141 }
142
143 &__column-title {
144 font-weight: 700;
145 font-size: 14px;
146 color: var(--neutral--600);
147 }
148
149 &__column-title--with-tooltip {
150 cursor: help;
151 }
152
153 &__row {
154 display: flex;
155 padding: 16px 0px;
156 }
157
158 &__cell {
159 display: flex;
160 align-items: center;
161
162 &--plugin {
163 width: 50%;
164 order: 1;
165 }
166
167 &--status {
168 width: 20%;
169 order: 2;
170 }
171
172 &--actions {
173 width: 10%;
174 display: flex;
175 justify-content: flex-end;
176 padding-right: 16px;
177 order: 3;
178 }
179 }
180
181 &__plugin-content {
182 display: flex;
183 align-items: center;
184 gap: 8px;
185 cursor: pointer;
186 width: 100%;
187 }
188
189 &__expand-button {
190 background: none;
191 border: none;
192 cursor: pointer;
193 padding: 0;
194 display: flex;
195 align-items: center;
196 justify-content: center;
197 width: 16px;
198 height: 16px;
199 }
200
201 &__plugin-info {
202 display: flex;
203 align-items: center;
204 gap: 12px;
205 }
206
207 &__plugin-icon {
208 width: 28px;
209 height: 28px;
210 border-radius: 7px;
211 overflow: hidden;
212 display: flex;
213 align-items: center;
214 justify-content: center;
215 background: var(--neutral--100);
216
217 img {
218 width: 100%;
219 height: 100%;
220 object-fit: contain;
221 }
222 }
223
224 &__plugin-name {
225 font-weight: 700;
226 font-size: 14px;
227 color: var(--neutral--500);
228 }
229
230 &__status-content {
231 display: flex;
232 align-items: center;
233 }
234
235 &__status-label {
236 font-size: 12px;
237 }
238
239 &__action-button {
240 background: var(--neutral--0);
241 border: 1px solid var(--neutral--200);
242 border-radius: 8px;
243 padding: 0 8px;
244 height: 32px;
245 display: flex;
246 align-items: center;
247 justify-content: center;
248 cursor: pointer;
249 transition: all 0.2s ease;
250
251 &:hover {
252 border-color: var(--neutral--300);
253 }
254 }
255
256 &__expansion-row {
257 width: 100%;
258 }
259
260 &__expansion-content {
261 background-color: var(--neutral--50);
262 border-radius: 12px;
263 padding: 16px 0;
264 display: flex;
265 flex-direction: column;
266 gap: 8px;
267 }
268
269 &__plugin-toggle-row {
270 display: flex;
271 align-items: center;
272
273 .plugin-entries-table__cell--plugin {
274 width: 50%;
275 padding-left: 16px;
276 }
277
278 .plugin-entries-table__cell--status {
279 width: 20%;
280 }
281
282 .plugin-entries-table__cell--actions {
283 width: 10%;
284 display: flex;
285 justify-content: flex-end;
286 padding-right: 16px;
287 }
288 }
289
290 &__forms-list {
291 display: flex;
292 flex-direction: column;
293 gap: 4px;
294 }
295
296 &__form-item {
297 display: flex;
298 align-items: center;
299 padding: 16px 0px;
300 border-top: 1px solid var(--neutral--200);
301
302 &:first-child {
303 border-top: none;
304 }
305
306 .plugin-entries-table__cell--plugin {
307 width: 50%;
308 padding-left: 32px;
309 }
310
311 .plugin-entries-table__cell--status {
312 width: 20%;
313 }
314
315 .plugin-entries-table__cell--actions {
316 width: 10%;
317 display: flex;
318 justify-content: flex-end;
319 padding-right: 16px;
320 }
321 }
322
323 &__form-info {
324 display: flex;
325 flex-direction: column;
326 gap: 2px;
327 }
328
329 &__form-id {
330 font-weight: 500;
331 font-size: 12px;
332 color: var(--neutral--600);
333 font-family: monospace;
334 }
335
336 &__form-title {
337 font-weight: 400;
338 font-size: 11px;
339 color: var(--neutral--500);
340 opacity: 0.8;
341 }
342
343 &__toggle-container {
344 display: flex;
345 align-items: center;
346 gap: 16px;
347 }
348
349 &__toggle-label {
350 font-weight: 400;
351 font-size: 14px;
352 color: var(--neutral--500);
353 }
354
355 &__entries-text {
356 font-weight: 400;
357 font-size: 14px;
358 color: var(--neutral--500);
359 }
360
361 &__popover-menu {
362 padding: 4px;
363 min-width: 180px;
364 }
365
366 &__menu-item {
367 display: flex;
368 align-items: center;
369 gap: 8px;
370 padding: 12px;
371 cursor: pointer;
372 border-radius: 8px;
373 font-weight: 500;
374 font-size: 14px;
375 color: var(--neutral--600);
376 transition: background-color 0.2s ease;
377
378 &:hover {
379 background-color: var(--neutral--50);
380 }
381
382 span {
383 flex: 1;
384 }
385 }
386
387 @media (max-width: 1023px) {
388 &__header {
389 display: none;
390 }
391 }
392 }
393 </style>
394