feat: share badge on social media
This commit is contained in:
90
frontend/src/pages/Badge.vue
Normal file
90
frontend/src/pages/Badge.vue
Normal file
@@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<div v-if="badge.doc">
|
||||
<div class="p-5 flex flex-col items-center mt-40">
|
||||
<div class="text-3xl font-semibold">
|
||||
{{ badge.doc.title }}
|
||||
</div>
|
||||
<img :src="badge.doc.image" :alt="badge.doc.title" class="h-60 mt-2" />
|
||||
<div class="text-lg">
|
||||
{{
|
||||
__('This badge has been awarded to {0} on {1}.').format(
|
||||
userName,
|
||||
dayjs(issuedOn.data?.issued_on).format('DD MMM YYYY')
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
<div class="text-lg mt-2">
|
||||
{{ badge.doc.description }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script setup>
|
||||
import { createDocumentResource, createResource, Breadcrumbs } from 'frappe-ui'
|
||||
import { computed, inject } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
|
||||
const allUsers = inject('$allUsers')
|
||||
const dayjs = inject('$dayjs')
|
||||
const router = useRouter()
|
||||
|
||||
const props = defineProps({
|
||||
badgeName: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
email: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
const badge = createDocumentResource({
|
||||
doctype: 'LMS Badge',
|
||||
name: props.badgeName,
|
||||
})
|
||||
|
||||
const userName = computed(() => {
|
||||
const user = Object.values(allUsers.data).find(
|
||||
(user) => user.name === props.email
|
||||
)
|
||||
return user ? user.full_name : props.email
|
||||
})
|
||||
|
||||
const issuedOn = createResource({
|
||||
url: 'frappe.client.get_value',
|
||||
makeParams(values) {
|
||||
return {
|
||||
doctype: 'LMS Badge Assignment',
|
||||
filters: {
|
||||
member: props.email,
|
||||
badge: props.badgeName,
|
||||
},
|
||||
fieldname: 'issued_on',
|
||||
}
|
||||
},
|
||||
onSuccess(data) {
|
||||
if (!data.issued_on) {
|
||||
router.push({ name: 'Courses' })
|
||||
}
|
||||
},
|
||||
auto: true,
|
||||
})
|
||||
|
||||
const breadcrumbs = computed(() => {
|
||||
return [
|
||||
{
|
||||
label: 'Badges',
|
||||
},
|
||||
{
|
||||
label: badge.doc.title,
|
||||
route: {
|
||||
name: 'Badge',
|
||||
params: {
|
||||
badge: badge.doc.name,
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
})
|
||||
</script>
|
||||
@@ -18,7 +18,7 @@
|
||||
</h2>
|
||||
<div class="grid grid-cols-5 gap-4">
|
||||
<div v-if="badges.data" v-for="badge in badges.data">
|
||||
<Popover trigger="hover" leaveDelay="0.01">
|
||||
<Popover trigger="hover" :leaveDelay="Number(0.01)">
|
||||
<template #target>
|
||||
<div class="relative">
|
||||
<img
|
||||
@@ -61,15 +61,26 @@
|
||||
<span class="text-xs text-gray-700 font-medium mb-1">
|
||||
{{ __('Share on') }}:
|
||||
</span>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
@click="shareOnLinkedIn(badge)"
|
||||
>
|
||||
<template #icon>
|
||||
<LinkedinIcon class="h-3 w-3 stroke-1.5" />
|
||||
</template>
|
||||
</Button>
|
||||
<div class="flex items-center space-x-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
@click="shareOnSocial(badge, 'LinkedIn')"
|
||||
>
|
||||
<template #icon>
|
||||
<LinkedinIcon
|
||||
class="h-3 w-3 stroke-1.5 text-gray-700"
|
||||
/>
|
||||
</template>
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
@click="shareOnSocial(badge, 'Twitter')"
|
||||
>
|
||||
<Twitter class="h-3 w-3 stroke-1.5 text-gray-700" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -82,7 +93,7 @@
|
||||
<script setup>
|
||||
import { inject } from 'vue'
|
||||
import { createResource, Popover, Button } from 'frappe-ui'
|
||||
import { X, LinkedinIcon } from 'lucide-vue-next'
|
||||
import { X, LinkedinIcon, Twitter } from 'lucide-vue-next'
|
||||
import { sessionStore } from '@/stores/session'
|
||||
|
||||
const dayjs = inject('$dayjs')
|
||||
@@ -117,16 +128,22 @@ const badges = createResource({
|
||||
},
|
||||
})
|
||||
|
||||
const shareOnLinkedIn = (badge) => {
|
||||
const url = encodeURIComponent(window.location.href)
|
||||
const image = url.split('/lms')[0] + badge.badge_image
|
||||
console.log(image)
|
||||
const shareOnSocial = (badge, medium) => {
|
||||
let shareUrl
|
||||
const url = encodeURIComponent(
|
||||
`${window.location.origin}/badges/${badge.badge}/${props.profile.data?.email}`
|
||||
)
|
||||
const summary = `I am happy to announce that I earned the ${
|
||||
badge.badge
|
||||
} badge on ${dayjs(badge.issued_on).format('DD MMM YYYY')} at ${
|
||||
branding.data?.brand_name
|
||||
}. Here's the badge I earned: ${image}`
|
||||
const shareUrl = `https://www.linkedin.com/shareArticle/?url=${url}&text=${summary}&submitted-image-url=${badge.badge_image}`
|
||||
}.`
|
||||
|
||||
if (medium == 'LinkedIn')
|
||||
shareUrl = `https://www.linkedin.com/shareArticle?mini=true&url=${url}&text=${summary}`
|
||||
else if (medium == 'Twitter')
|
||||
shareUrl = `https://twitter.com/intent/tweet?text=${summary}&url=${url}`
|
||||
|
||||
window.open(shareUrl, '_blank')
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -135,6 +135,12 @@ const routes = [
|
||||
name: 'Notifications',
|
||||
component: () => import('@/pages/Notifications.vue'),
|
||||
},
|
||||
{
|
||||
path: '/badges/:badgeName/:email',
|
||||
name: 'Badge',
|
||||
component: () => import('@/pages/Badge.vue'),
|
||||
props: true,
|
||||
},
|
||||
]
|
||||
|
||||
let router = createRouter({
|
||||
@@ -154,7 +160,8 @@ router.beforeEach(async (to, from, next) => {
|
||||
isLoggedIn &&
|
||||
(to.name == 'Lesson' ||
|
||||
to.name == 'Batch' ||
|
||||
to.name == 'Notifications')
|
||||
to.name == 'Notifications' ||
|
||||
to.name == 'Badge')
|
||||
) {
|
||||
await allUsers.reload()
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@
|
||||
"link_fieldname": "badge"
|
||||
}
|
||||
],
|
||||
"modified": "2024-05-14 14:46:13.644382",
|
||||
"modified": "2024-05-27 17:25:55.399830",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "LMS Badge",
|
||||
@@ -116,6 +116,15 @@
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "All",
|
||||
"share": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "creation",
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
<meta name="twitter:title" content="{{ meta.title }}" />
|
||||
<meta name="twitter:image" content="{{ meta.image }}" />
|
||||
<meta name="twitter:description" content="{{ meta.description }}" />
|
||||
<script type="module" crossorigin src="/assets/lms/frontend/assets/index-DH4LPAyv.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/lms/frontend/assets/frappe-ui-Cdm1MNHD.js">
|
||||
<script type="module" crossorigin src="/assets/lms/frontend/assets/index-BCIMZEe3.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/lms/frontend/assets/frappe-ui-D-bJ8Xgf.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/lms/frontend/assets/frappe-ui-B1gEXx4C.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/lms/frontend/assets/index-CfA8Gbx1.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/lms/frontend/assets/index-B_uDyhcC.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
|
||||
@@ -130,3 +130,20 @@ def get_meta(app_path):
|
||||
"keywords": f"{user.full_name}, {user.bio}",
|
||||
"link": f"/user/{username}",
|
||||
}
|
||||
|
||||
if re.match(r"^badges/.*/.*$", app_path):
|
||||
badgeName = app_path.split("/")[1]
|
||||
email = app_path.split("/")[2]
|
||||
badge = frappe.db.get_value(
|
||||
"LMS Badge",
|
||||
badgeName,
|
||||
["title", "image", "description"],
|
||||
as_dict=True,
|
||||
)
|
||||
return {
|
||||
"title": badge.title,
|
||||
"image": badge.image,
|
||||
"description": badge.description,
|
||||
"keywords": f"{badge.title}, {badge.description}",
|
||||
"link": f"/badges/{badgeName}/{email}",
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user