Browse Source

Merge remote-tracking branch 'refs/remotes/origin/markeds-pop-up' into dashboard-layout

# Conflicts:
#	gca-admin-gurusoft-message-dashboard/src/App.vue
#	gca-admin-gurusoft-message-dashboard/src/main.js
#	gca-admin-gurusoft-message-dashboard/src/router/index.js
dashboard-layout
ken 7 months ago
parent
commit
bfae070293
9 changed files with 398 additions and 7 deletions
  1. +1
    -0
      gca-admin-gurusoft-message-dashboard/.env
  2. +1
    -1
      gca-admin-gurusoft-message-dashboard/README.md
  3. +52
    -0
      gca-admin-gurusoft-message-dashboard/src/components/FakePage.vue
  4. +118
    -0
      gca-admin-gurusoft-message-dashboard/src/components/MarkedPopUp.vue
  5. +97
    -0
      gca-admin-gurusoft-message-dashboard/src/components/SystemLinks.vue
  6. +1
    -1
      gca-admin-gurusoft-message-dashboard/src/main.js
  7. +62
    -0
      gca-admin-gurusoft-message-dashboard/src/mocks/marketPopUpMockData.json
  8. +62
    -0
      gca-admin-gurusoft-message-dashboard/src/mocks/systemLinksMockData.json
  9. +4
    -5
      gca-admin-gurusoft-message-dashboard/src/router/index.js

+ 1
- 0
gca-admin-gurusoft-message-dashboard/.env View File

@ -0,0 +1 @@
VITE_USE_MOCK=true

+ 1
- 1
gca-admin-gurusoft-message-dashboard/README.md View File

@ -1,4 +1,4 @@
# gca-admin-gurusoft-message-dashboard
npm # gca-admin-gurusoft-message-dashboard
This template should help get you started developing with Vue 3 in Vite. This template should help get you started developing with Vue 3 in Vite.

+ 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>

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

@ -0,0 +1,118 @@
<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
}
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];
}
loading.value = false;
}
} catch (e) {
error.value = e.message;
loading.value = false;
}
});
const togglePopup = () => {
showPopup.value = !showPopup.value;
};
const closePopup = () => {
showPopup.value = false;
};
const handleAction = () => {
if (currentPopup.value?.url) {
window.open(currentPopup.value.url, '_blank');
}
closePopup();
};
</script>
<template>
<button v-if="!showPopup" @click="togglePopup" class="btn btn-primary">
Show Popup
</button>
<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>

+ 97
- 0
gca-admin-gurusoft-message-dashboard/src/components/SystemLinks.vue View File

@ -0,0 +1,97 @@
<template>
<div v-if="loading">Loading...</div>
<div v-else-if="error">Error: {{ error }}</div>
<div v-else class="container p-3 border overflow-auto" style="max-height: 340px; width: 420px;">
<div
v-for="(link, index) in links"
:key="index"
class="mb-2"
>
<a
:href="link.url"
class="btn d-flex align-items-center text-start w-100 px-4 py-3"
:class="getButtonClass(link.type)"
:style="{ borderRadius: buttonRadius }"
target="_blank"
>
<i :class="getIconClass(link.icon)" class="me-2"></i>
{{ link.text }}
</a>
</div>
</div>
</template>
<script setup>
import {ref, onMounted, defineProps} from 'vue';
import linkData from '@/mocks/systemLinksMockData.json';
const props = defineProps({
elementId: {
type: String,
required: true
},
metrics: {
type: [String, Object, Array],
default: null
},
buttonRadius: {
type: String,
default: '0.0rem'
},
useMockedData: {
type: Boolean,
default: true
}
});
const links = ref([]);
const loading = ref(true);
const error = ref(null);
const getButtonClass = (type) => {
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';
}
};
const getIconClass = (icon) => `bi bi-${icon}`;
onMounted(async () => {
try {
if (props.useMockedData) {
// Use mock
links.value = linkData;
loading.value = false;
} else {
// Fetch from API
const response = await fetch(`https://TODO-replace-with-API`);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
links.value = await response.json();
}
} catch (err) {
error.value = err.message;
} finally {
loading.value = false;
}
});
</script>
<style scoped>
.container {
background-color: #f8f9fa;
border: 1px solid #ddd;
overflow-y: auto;
}
</style>

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

@ -1,6 +1,6 @@
import './assets/main.css' import './assets/main.css'
import {createApp} from 'vue'
import { createApp } from 'vue'
import App from './App.vue' import App from './App.vue'
import router from './router'; import router from './router';

+ 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"
}
]

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

@ -0,0 +1,62 @@
[
{
"url": "https://report.gurusoft.no/",
"text": "Gurusoft hjemmeside",
"type": "admin",
"icon": "dashboard"
},
{
"url": "https://www.gurusoft.no/ta-kontakt?utm_term=gurusoft&utm_campaign=Search+-+Gurusoft+-+Brand&utm_source=adwords&utm_medium=ppc&hsa_acc=1671275617&hsa_cam=21429497412&hsa_grp=164723437872&hsa_ad=704644852789&hsa_src=g&hsa_tgt=kwd-357983112442&hsa_kw=gurusoft&hsa_mt=b&hsa_net=adwords&hsa_ver=3&gad_source=1&gad_campaignid=21429497412&gbraid=0AAAAAC6-h5QA-Uem3fnf9a8Q7l0FhCFkF&gclid=CjwKCAjw3_PCBhA2EiwAkH_j4oYc5_RLO87_7JXoxRBwBR3sR7mHymCM5WRcyM_ORAb7kcmDvoi-HBoCxR4QAvD_BwE",
"text": "Kontakt oss",
"type": "internal",
"icon": "book"
},
{
"url": "https://open.spotify.com/show/4iPq4aLAWHbsXpg0dKSGnY?si=c9ae69117a5740fd&nd=1&dlsi=328d8504668c4558",
"text": "Musikk innslag",
"type": "internal",
"icon": "support"
},
{
"url": "https://www.company.com/privacy-policy",
"text": "Privacy Policy",
"type": "external",
"icon": "policy"
},
{
"url": "https://www.company.com/terms-of-service",
"text": "Terms of Service",
"type": "what",
"icon": "terms"
},
{
"url": "https://intranet.company.local/dashboard",
"text": "Admin Dashboard",
"type": "admin",
"icon": "dashboard"
},
{
"url": "https://google.com",
"text": "Knowledge Base",
"type": "internal",
"icon": "book"
},
{
"url": "https://intranet.company.local/support",
"text": "Support",
"type": "internal",
"icon": "support"
},
{
"url": "https://www.company.com/privacy-policy",
"text": "Privacy Policy",
"type": "external",
"icon": "policy"
},
{
"url": "https://www.company.com/terms-of-service",
"text": "Terms of Service",
"type": "what",
"icon": "terms"
}
]

+ 4
- 5
gca-admin-gurusoft-message-dashboard/src/router/index.js View File

@ -2,12 +2,11 @@ import {createRouter, createWebHistory} from 'vue-router';
import SystemMessagesPage from '../components/SystemMessagesPage.vue'; import SystemMessagesPage from '../components/SystemMessagesPage.vue';
import SystemMessages from '../components/SystemMesssages.vue'; import SystemMessages from '../components/SystemMesssages.vue';
import Dashboard from '../components/Dashboard.vue'; import Dashboard from '../components/Dashboard.vue';
import FakePage from '../components/FakePage.vue'
import SystemLinks from '../components/SystemLinks.vue'
import MarkedPopUp from '../components/MarkedPopUp.vue'
const routes = [
{path: '/systemmessage', name: 'SystemMessage', component: SystemMessages},
{path: '/systemmessagelist', name: 'SystemMessageList', component: SystemMessagesPage},
{path: '/dashboard', name: 'Dashboard', component: Dashboard}
];
const router = createRouter({ const router = createRouter({
history: createWebHistory(), history: createWebHistory(),

Loading…
Cancel
Save