Browse Source

Feat: Added pop-up which is executed when page is loaded

markeds-pop-up
johan 7 months ago
parent
commit
723dfd87bb
7 changed files with 264 additions and 21 deletions
  1. +5
    -9
      gca-admin-gurusoft-message-dashboard/src/App.vue
  2. +52
    -0
      gca-admin-gurusoft-message-dashboard/src/components/FakePage.vue
  3. +110
    -0
      gca-admin-gurusoft-message-dashboard/src/components/MarkedPopUp.vue
  4. +15
    -10
      gca-admin-gurusoft-message-dashboard/src/components/SystemLinks.vue
  5. +3
    -2
      gca-admin-gurusoft-message-dashboard/src/main.js
  6. +62
    -0
      gca-admin-gurusoft-message-dashboard/src/mocks/marketPopUpMockData.json
  7. +17
    -0
      gca-admin-gurusoft-message-dashboard/src/router/index.js

+ 5
- 9
gca-admin-gurusoft-message-dashboard/src/App.vue View File

@ -2,6 +2,8 @@
import 'bootstrap/dist/css/bootstrap.min.css'; import 'bootstrap/dist/css/bootstrap.min.css';
import SystemLinks from "@/components/SystemLinks.vue"; import SystemLinks from "@/components/SystemLinks.vue";
import {inject} from 'vue' import {inject} from 'vue'
import FakePage from "@/components/FakePage.vue";
import MarkedPopUp from "@/components/MarkedPopUp.vue";
const externalData = inject("externalData", {}) const externalData = inject("externalData", {})
const useMockedData = import.meta.env.VITE_USE_MOCK === "true" const useMockedData = import.meta.env.VITE_USE_MOCK === "true"
@ -10,15 +12,9 @@ const useMockedData = import.meta.env.VITE_USE_MOCK === "true"
</script> </script>
<template> <template>
<main>
<div>
<component
:is="SystemLinks"
elementId="system-links"
:useMockedData="useMockedData"
/>
</div>
</main>
<div class="app">
<router-view/>
</div>
</template> </template>
<style scoped> <style scoped>

+ 52
- 0
gca-admin-gurusoft-message-dashboard/src/components/FakePage.vue View File

@ -0,0 +1,52 @@
<script setup lang="ts">
import MarkedPopUp from "@/components/MarkedPopUp.vue";
// Define button styles with different colors
const buttons = [
{text: 'Google Search', url: 'https://www.google.com', class: 'btn-primary'},
{text: 'Google Maps', url: 'https://maps.google.com', class: 'btn-success'},
{text: 'Google Drive', url: 'https://drive.google.com', class: 'btn-warning'},
{text: 'Gmail', url: 'https://mail.google.com', class: 'btn-danger'}
];
// Lorem ipsum text for demonstration
const loremText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. ".repeat(100);
</script>
<template>
<MarkedPopUp element-id="fake-page-popup" :use-mocked-data="true"/>
<div class="container p-2">
<h1 class="mb-4">Fake Page Example</h1>
<!-- Buttons section - now full width and above text -->
<div class="p-1">
<div class="card-header p-2">Google Services</div>
<div class="card-body p-2">
<div class="row">
<div v-for="(button, index) in buttons" :key="index" class="col-md-3 mb-2">
<a :href="button.url" class="btn w-100" :class="button.class" target="_blank">
{{ button.text }}
</a>
</div>
</div>
</div>
</div>
<!-- Text section - now without scrollable container -->
<div class="p-3 ">
<div class="card-header">Text Content</div>
<div class="card-body">
<p>{{ loremText }}</p>
</div>
</div>
</div>
</template>
<style scoped>
.card-header {
font-weight: bold;
background-color: #f8f9fa;
}
</style>

+ 110
- 0
gca-admin-gurusoft-message-dashboard/src/components/MarkedPopUp.vue View File

@ -0,0 +1,110 @@
<script setup>
import {ref, onMounted, defineProps} from 'vue';
import popupData from '@/mocks/marketPopUpMockData.json';
const props = defineProps({
elementId: {
type: String,
required: true
},
useMockedData: {
type: Boolean,
default: false
}
});
const popups = ref([]);
const currentPopup = ref(null);
const loading = ref(true);
const error = ref(null);
const showPopup = ref(false);
onMounted(async () => {
try {
if (props.useMockedData) {
// Use mock data
popups.value = popupData;
if (popups.value.length > 0) {
currentPopup.value = popups.value[4]; // Display first popup
showPopup.value = true;
}
loading.value = false;
} else {
// Fetch from API
const response = await fetch(`https://TODO-replace-with-API`);
if (!response.ok) {
throw new Error('Failed to fetch popup data');
}
popups.value = await response.json();
if (popups.value.length > 0) {
currentPopup.value = popups.value[0];
showPopup.value = true;
}
loading.value = false;
}
} catch (e) {
error.value = e.message;
loading.value = false;
}
});
const closePopup = () => {
showPopup.value = false;
};
const handleAction = () => {
if (currentPopup.value?.url) {
window.open(currentPopup.value.url, '_blank');
}
closePopup();
};
</script>
<template>
<div v-if="loading">Loading...</div>
<div v-else-if="error">Error: {{ error }}</div>
<div v-else-if="showPopup && currentPopup"
class="position-fixed bottom-0 end-0 m-4 shadow-lg p-3 bg-white rounded border"
style="z-index: 1080; max-width: 350px;">
<!-- Image section -->
<div v-if="currentPopup.image" class="mb-3">
<img :src="currentPopup.image" alt="Campaign image" class="img-fluid rounded popup-image">
</div>
<h4 class="mb-1 text fw-bold">{{ currentPopup.title }}</h4>
<!-- Added ingress field -->
<p v-if="currentPopup.ingress" class="mb-1 fw-bold small">
{{ currentPopup.ingress }}
</p>
<p class="mb-2 small">
{{ currentPopup.description }}
</p>
<div class="d-flex justify-content-end gap-2">
<button @click="closePopup" class="btn btn-outline-secondary btn-sm">Lukk</button>
<button @click="handleAction" class="btn btn-primary btn-sm">
{{ currentPopup.linkText || 'Se mer' }}
</button>
</div>
</div>
</template>
<style scoped>
.shadow-lg {
box-shadow: 0 1rem 3rem rgba(0, 0, 0, 0.175) !important;
}
.rounded {
border-radius: 0.375rem !important;
}
.popup-image {
width: 100%;
object-fit: cover;
max-height: 180px;
}
</style>

+ 15
- 10
gca-admin-gurusoft-message-dashboard/src/components/SystemLinks.vue View File

@ -1,7 +1,7 @@
<template> <template>
<div v-if="loading">Loading...</div> <div v-if="loading">Loading...</div>
<div v-else-if="error">Error: {{ error }}</div> <div v-else-if="error">Error: {{ error }}</div>
<div v-else class="system-links-container p-3 border overflow-auto" style="max-height: 340px; width: 420px;">
<div v-else class="container p-3 border overflow-auto" style="max-height: 340px; width: 420px;">
<div <div
v-for="(link, index) in links" v-for="(link, index) in links"
:key="index" :key="index"
@ -22,7 +22,7 @@
</template> </template>
<script setup> <script setup>
import { ref, onMounted, defineProps } from 'vue';
import {ref, onMounted, defineProps} from 'vue';
import linkData from '@/mocks/systemLinksMockData.json'; import linkData from '@/mocks/systemLinksMockData.json';
const props = defineProps({ const props = defineProps({
@ -40,7 +40,7 @@ const props = defineProps({
}, },
useMockedData: { useMockedData: {
type: Boolean, type: Boolean,
default: false
default: true
} }
}); });
@ -50,11 +50,16 @@ const error = ref(null);
const getButtonClass = (type) => { const getButtonClass = (type) => {
switch (type?.toLowerCase()) { switch (type?.toLowerCase()) {
case 'internal': return 'btn-secondary opacity-75';
case 'external': return 'btn-success opacity-75';
case 'admin': return 'btn-warning opacity-75';
case 'system': return 'btn-light opacity-75';
default: return 'btn-info opacity-75';
case 'internal':
return 'btn-secondary opacity-75';
case 'external':
return 'btn-success opacity-75';
case 'admin':
return 'btn-warning opacity-75';
case 'system':
return 'btn-light opacity-75';
default:
return 'btn-info opacity-75';
} }
}; };
@ -67,7 +72,7 @@ onMounted(async () => {
links.value = linkData; links.value = linkData;
loading.value = false; loading.value = false;
} else { } else {
// Fetch from API - this part should never run when using mock data
// Fetch from API
const response = await fetch(`https://TODO-replace-with-API`); const response = await fetch(`https://TODO-replace-with-API`);
if (!response.ok) { if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`); throw new Error(`HTTP error! status: ${response.status}`);
@ -84,7 +89,7 @@ onMounted(async () => {
</script> </script>
<style scoped> <style scoped>
.system-links-container {
.container {
background-color: #f8f9fa; background-color: #f8f9fa;
border: 1px solid #ddd; border: 1px solid #ddd;
overflow-y: auto; overflow-y: auto;

+ 3
- 2
gca-admin-gurusoft-message-dashboard/src/main.js View File

@ -1,7 +1,8 @@
import './assets/main.css' import './assets/main.css'
import 'bootstrap/dist/css/bootstrap.min.css' import 'bootstrap/dist/css/bootstrap.min.css'
import { createApp } from 'vue'
import {createApp} from 'vue'
import App from './App.vue' import App from './App.vue'
import router from "./router";
createApp(App).mount('#app')
createApp(App).use(router).mount('#app')

+ 62
- 0
gca-admin-gurusoft-message-dashboard/src/mocks/marketPopUpMockData.json View File

@ -0,0 +1,62 @@
[
{
"title": "Sommertilbud!",
"ingress": "Få opptil 50% rabatt",
"description": "Spar stort på sommerens mest populære varer. Tilbudet varer ut uken.Spar stort på sommerens mest populære varer. Tilbudet varer ut ukenSpar stort på sommerens mest populære varer. Tilbudet varer ut ukenSpar stort på sommerens mest populære varer. Tilbudet varer ut ukenSpar stort på sommerens mest populære varer. Tilbudet varer ut ukenSpar stort på sommerens mest populære varer. Tilbudet varer ut ukenSpar stort på sommerens mest populære varer. Tilbudet varer ut uken",
"url": "https://google.com",
"linkText": "Les mer",
"image": "https://yavuzceliker.github.io/sample-images/image-92.jpg",
"type": "campaign",
"date": "2025-06-27"
},
{
"title": "Ny funksjon i appen",
"ingress": "Chat med oss direkte",
"description": "Vi har lansert en ny chat-funksjon hvor du kan få hjelp på sekunder.",
"url": "https://example.com/chat-funksjon",
"linkText": "Se hvordan",
"image": "https://yavuzceliker.github.io/sample-images/image-632.jpg",
"type": "feature",
"date": "2025-06-26"
},
{
"title": "Viktig informasjon",
"ingress": "Endringer i bruksvilkår",
"description": "Vi har oppdatert våre vilkår og personvernregler. Les mer om endringene her.",
"url": "https://example.com/vilkar",
"linkText": "Les nye vilkår",
"image": "https://yavuzceliker.github.io/sample-images/image-1.jpg",
"type": "notice",
"date": "2025-06-25"
},
{
"title": "Bli med på undersøkelse",
"ingress": "Hjelp oss å bli bedre",
"description": "Ta vår 2-minutters undersøkelse og vær med i trekningen av gavekort.",
"url": "https://example.com/undersokelse",
"linkText": "Svar nå",
"image": "https://yavuzceliker.github.io/sample-images/image-312.jpg",
"type": "survey",
"date": "2025-06-24"
},
{
"title": "Vi er her for deg",
"ingress": "Ny kundeserviceportal",
"description": "Oppdag vårt nye hjelpesenter med artikler, guider og live-hjelp.",
"url": "https://example.com/hjelp",
"linkText": "Gå til hjelpesenter",
"image": "https://yavuzceliker.github.io/sample-images/image-460.jpg",
"type": "support",
"date": "2025-06-23"
},
{
"title": "Eksklusivt webinartilbud",
"ingress": "Lær av ekspertene",
"description": "Bli med på vårt gratis webinar om digital markedsføring. Begrenset med plasser.",
"url": "https://example.com/webinar",
"linkText": "Meld deg på",
"image": "https://yavuzceliker.github.io/sample-images/image-699.jpg",
"type": "event",
"date": "2025-06-22"
}
]

+ 17
- 0
gca-admin-gurusoft-message-dashboard/src/router/index.js View File

@ -0,0 +1,17 @@
import {createRouter, createWebHistory} from 'vue-router'
import FakePage from '../components/FakePage.vue'
import SystemLinks from '../components/SystemLinks.vue'
import MarkedPopUp from '../components/MarkedPopUp.vue'
const routes = [
{path: '/', name: 'Home', component: FakePage},
{path: '/system-links', name: 'SystemLinks', component: SystemLinks},
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router

Loading…
Cancel
Save