PluginProbe ʕ •ᴥ•ʔ
Hostinger Reach – AI-Powered Email Marketing for WordPress / 1.0.5
Hostinger Reach – AI-Powered Email Marketing for WordPress v1.0.5
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 / views / OverviewView.vue
hostinger-reach / frontend / vue / views Last commit date
OverviewView.vue 9 months ago WelcomeView.vue 9 months ago
OverviewView.vue
319 lines
1 <script setup lang="ts">
2 import { computed, onMounted } from 'vue';
3
4 import reachLogo from '@/assets/images/icons/reach-logo.svg';
5 import ActionButtonsSection from '@/components/ActionButtonsSection.vue';
6 import FormsSection from '@/components/FormsSection.vue';
7 import UsageCardsSection from '@/components/UsageCardsSection.vue';
8 import { useModal } from '@/composables';
9 import { useOverviewData } from '@/composables/useOverviewData';
10 import { useReachUrls } from '@/composables/useReachUrls';
11 import { useToast } from '@/composables/useToast';
12 import { formsRepo } from '@/data/repositories/formsRepo';
13 import { useIntegrationsStore } from '@/stores/integrationsStore';
14 import { ModalName } from '@/types';
15 import type { Form } from '@/types/models';
16 import { translate } from '@/utils/translate';
17
18 const { isLoading, usageCards, loadOverviewData } = useOverviewData();
19 const { reachUpgradeLink, reachYourPlanLink, reachCampaignsLink, reachTemplatesLink, reachSettingsLink } =
20 useReachUrls();
21 const { showError } = useToast();
22
23 const { openModal } = useModal();
24 const integrationsStore = useIntegrationsStore();
25
26 const actionButtons = computed(() => [
27 {
28 icon: 'ic-graph-arrow-up-16',
29 text: translate('hostinger_reach_overview_campaigns_text'),
30 url: reachCampaignsLink.value
31 },
32 {
33 icon: 'ic-sparkles-16',
34 text: translate('hostinger_reach_overview_templates_text'),
35 url: reachTemplatesLink.value
36 },
37 {
38 icon: 'ic-gear-16',
39 text: translate('hostinger_reach_overview_settings_text'),
40 url: reachSettingsLink.value
41 }
42 ]);
43
44 const handlePluginGoTo = (id: string) => {
45 const integration = integrationsStore.integrations.find((i) => i.id === id);
46 if (!integration?.adminUrl) {
47 return;
48 }
49
50 window.open(integration.adminUrl, '_blank');
51 };
52
53 const handlePluginDisconnect = (id: string) => {
54 openModal(ModalName.CONFIRM_DISCONNECT_MODAL, {
55 data: { integration: id }
56 });
57 };
58
59 const handleFormToggleStatus = async (form: Form, status: boolean) => {
60 if (form.isLoading) {
61 return;
62 }
63
64 const integration = integrationsStore.integrations.find((i) => i.forms?.some((f) => f.formId === form.formId));
65 if (!integration || !integration.forms) {
66 return;
67 }
68
69 const formIndex = integration.forms.findIndex((f) => f.formId === form.formId);
70 if (formIndex !== -1) {
71 integration.forms[formIndex].isLoading = true;
72 }
73
74 const [, error] = await formsRepo.toggleFormStatus(form.formId, status);
75
76 if (formIndex !== -1) {
77 integration.forms[formIndex].isLoading = false;
78 }
79
80 if (error) {
81 showError(translate('hostinger_reach_error_message'));
82
83 return;
84 }
85
86 if (formIndex !== -1) {
87 integration.forms[formIndex] = {
88 ...integration.forms[formIndex],
89 isActive: status
90 };
91 }
92 };
93
94 const handleViewForm = (form: Form) => {
95 if (form.formId === 'ai-theme-footer-form') {
96 window.open(hostinger_reach_reach_data.site_url, '_blank');
97 }
98
99 if (form.post?.guid) {
100 window.open(form.post.guid, '_blank');
101 }
102 };
103
104 const handleEditForm = (form: Form) => {
105 const integration = integrationsStore.integrations.find((i) => i.forms?.some((f) => f.formId === form.formId));
106
107 if (!integration?.editUrl) {
108 return;
109 }
110
111 let editUrl = integration.editUrl;
112
113 if (editUrl.includes('{post_id}')) {
114 editUrl = editUrl.replace('{post_id}', form.post?.ID.toString() ?? '');
115 } else if (editUrl.includes('{form_id}')) {
116 editUrl = editUrl.replace('{form_id}', form.formId);
117 }
118
119 if (form.formId === 'ai-theme-footer-form') {
120 editUrl = 'site-editor.php?p=%2Fwp_template_part%2Fhostinger-ai-theme%2F%2Ffooter&canvas=edit';
121 }
122
123 if (!editUrl.startsWith('http') && !editUrl.startsWith('/')) {
124 editUrl = `/wp-admin/${editUrl}`;
125 }
126
127 window.open(editUrl, '_blank');
128 };
129
130 onMounted(() => {
131 loadOverviewData();
132 integrationsStore.loadIntegrations();
133 });
134 </script>
135
136 <template>
137 <div class="overview">
138 <header class="overview__header">
139 <div class="overview__header-content">
140 <div class="overview__header-brand">
141 <img :src="reachLogo" :alt="translate('hostinger_reach_header_logo_alt')" class="overview__header-logo" />
142 </div>
143 </div>
144 </header>
145
146 <div class="overview__content">
147 <div class="overview__section">
148 <div class="overview__title">
149 <HText as="h1" variant="heading-1">
150 {{ translate('hostinger_reach_overview_title') }}
151 </HText>
152 <div class="overview__title-buttons">
153 <HButton
154 variant="text"
155 color="primary"
156 size="small"
157 icon-append="ic-arrow-up-right-square-16"
158 :to="reachYourPlanLink"
159 target="_blank"
160 class="overview__your-plan-button"
161 >
162 {{ translate('hostinger_reach_overview_your_plan_button') }}
163 </HButton>
164 <HButton
165 variant="outline"
166 color="primary"
167 size="small"
168 icon-prepend="ic-lightning-16"
169 :to="reachUpgradeLink"
170 target="_blank"
171 class="overview__upgrade-button"
172 >
173 {{ translate('hostinger_reach_overview_upgrade_button') }}
174 </HButton>
175 </div>
176 </div>
177 <div class="overview__section-content">
178 <UsageCardsSection :usage-cards="usageCards" :is-loading="isLoading" />
179 <ActionButtonsSection :buttons="actionButtons" />
180 </div>
181 </div>
182
183 <FormsSection
184 @go-to-plugin="handlePluginGoTo"
185 @disconnect-plugin="handlePluginDisconnect"
186 @toggle-form-status="handleFormToggleStatus"
187 @view-form="handleViewForm"
188 @edit-form="handleEditForm"
189 />
190 </div>
191 </div>
192 </template>
193
194 <style scoped lang="scss">
195 .overview {
196 min-height: 100vh;
197 background-color: var(--neutral--50);
198
199 &__header {
200 width: 100%;
201 padding: 40px 0 20px 0;
202 @media (max-width: 768px) {
203 padding: 16px 12px;
204 }
205
206 @media (max-width: 480px) {
207 padding: 12px 8px;
208 }
209 }
210
211 &__header-content {
212 display: flex;
213 justify-content: flex-start;
214 align-items: center;
215 width: 860px;
216 margin: 0 auto;
217
218 @media (max-width: 1023px) {
219 width: 100%;
220 }
221 }
222
223 &__header-brand {
224 display: flex;
225 align-items: center;
226 gap: 12px;
227
228 @media (max-width: 480px) {
229 gap: 8px;
230 }
231 }
232
233 &__header-logo {
234 height: 28px;
235 width: auto;
236
237 @media (max-width: 768px) {
238 height: 24px;
239 }
240
241 @media (max-width: 480px) {
242 height: 20px;
243 }
244 }
245
246 &__content {
247 display: flex;
248 flex-direction: column;
249 align-items: flex-end;
250 gap: 32px;
251 padding: 20px 0 0;
252 width: 860px;
253 margin: 0 auto;
254 }
255
256 &__section {
257 display: flex;
258 flex-direction: column;
259 align-self: stretch;
260 gap: 20px;
261 }
262
263 &__title {
264 display: flex;
265 justify-content: space-between;
266 align-items: center;
267 align-self: stretch;
268 }
269
270 &__title-buttons {
271 display: flex;
272 align-items: center;
273 gap: 8px;
274 }
275
276 &__your-plan-button {
277 margin-right: 0;
278 }
279
280 &__upgrade-button {
281 background: var(--neutral--0);
282 border: 1px solid transparent;
283 background-image:
284 linear-gradient(var(--neutral--0), var(--neutral--0)),
285 linear-gradient(135deg, var(--primary--200) 0%, var(--primary--400) 47.45%, var(--primary--600) 100%);
286 background-origin: border-box;
287 background-clip: padding-box, border-box;
288 color: var(--neutral--600);
289 }
290
291 &__section-content {
292 display: flex;
293 flex-direction: column;
294 align-self: stretch;
295 gap: 16px;
296 }
297 }
298
299 @media (max-width: 1023px) {
300 .overview {
301 &__content {
302 width: 100%;
303 padding: 24px 16px 0;
304 }
305
306 &__title {
307 flex-direction: column;
308 align-items: flex-start;
309 gap: 12px;
310 }
311
312 &__title-buttons {
313 align-self: stretch;
314 justify-content: flex-end;
315 }
316 }
317 }
318 </style>
319