| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
d3e706f9c5 | feat: add systemlink and marked pop-up component | 7 months ago |
|
|
bfae070293 |
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 |
7 months ago |
|
|
96eec70b26 | Feat: Added pop-up which is executed when toggled/page load if wanted | 7 months ago |
|
|
723dfd87bb | Feat: Added pop-up which is executed when page is loaded | 7 months ago |
|
|
33d2ff6049 | Feat: Added page with basic styling for System Links component | 7 months ago |
|
|
5ebca991ab | Feat: Added page with basic styling for System Links component | 7 months ago |
| @ -0,0 +1,21 @@ | |||||
| <component name="InspectionProjectProfileManager"> | |||||
| <profile version="1.0"> | |||||
| <option name="myName" value="Project Default" /> | |||||
| <inspection_tool class="HtmlUnknownTag" enabled="true" level="WARNING" enabled_by_default="true"> | |||||
| <option name="myValues"> | |||||
| <value> | |||||
| <list size="7"> | |||||
| <item index="0" class="java.lang.String" itemvalue="nobr" /> | |||||
| <item index="1" class="java.lang.String" itemvalue="noembed" /> | |||||
| <item index="2" class="java.lang.String" itemvalue="comment" /> | |||||
| <item index="3" class="java.lang.String" itemvalue="noscript" /> | |||||
| <item index="4" class="java.lang.String" itemvalue="embed" /> | |||||
| <item index="5" class="java.lang.String" itemvalue="script" /> | |||||
| <item index="6" class="java.lang.String" itemvalue="router-link" /> | |||||
| </list> | |||||
| </value> | |||||
| </option> | |||||
| <option name="myCustomValuesEnabled" value="true" /> | |||||
| </inspection_tool> | |||||
| </profile> | |||||
| </component> | |||||
| @ -0,0 +1,6 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <project version="4"> | |||||
| <component name="JavaScriptLibraryMappings"> | |||||
| <file url="file://$PROJECT_DIR$" libraries="{bootstrap}" /> | |||||
| </component> | |||||
| </project> | |||||
| @ -0,0 +1,6 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <project version="4"> | |||||
| <component name="PrettierConfiguration"> | |||||
| <option name="myConfigurationMode" value="AUTOMATIC" /> | |||||
| </component> | |||||
| </project> | |||||
| @ -0,0 +1 @@ | |||||
| VITE_USE_MOCK=true | |||||
| @ -0,0 +1,114 @@ | |||||
| <script setup> | |||||
| import {ref, onMounted, defineProps} from 'vue'; | |||||
| import popupData from '@/mocks/marketPopUpMockData.json'; | |||||
| const props = defineProps({ | |||||
| useMockedData: { | |||||
| type: Boolean, | |||||
| default: true | |||||
| } | |||||
| }); | |||||
| 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> | |||||
| @ -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> | |||||
| @ -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" | |||||
| } | |||||
| ] | |||||
| @ -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" | |||||
| } | |||||
| ] | |||||
| @ -0,0 +1,6 @@ | |||||
| { | |||||
| "name": "sommer2025", | |||||
| "lockfileVersion": 3, | |||||
| "requires": true, | |||||
| "packages": {} | |||||
| } | |||||