feat: share badge on social media

This commit is contained in:
Jannat Patel
2024-05-28 12:05:16 +05:30
parent d03dd3d20d
commit 7c077ace95
6 changed files with 162 additions and 22 deletions

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

View File

@@ -18,7 +18,7 @@
</h2> </h2>
<div class="grid grid-cols-5 gap-4"> <div class="grid grid-cols-5 gap-4">
<div v-if="badges.data" v-for="badge in badges.data"> <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> <template #target>
<div class="relative"> <div class="relative">
<img <img
@@ -61,15 +61,26 @@
<span class="text-xs text-gray-700 font-medium mb-1"> <span class="text-xs text-gray-700 font-medium mb-1">
{{ __('Share on') }}: {{ __('Share on') }}:
</span> </span>
<Button <div class="flex items-center space-x-2">
variant="outline" <Button
size="sm" variant="outline"
@click="shareOnLinkedIn(badge)" size="sm"
> @click="shareOnSocial(badge, 'LinkedIn')"
<template #icon> >
<LinkedinIcon class="h-3 w-3 stroke-1.5" /> <template #icon>
</template> <LinkedinIcon
</Button> 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> </div>
</div> </div>
@@ -82,7 +93,7 @@
<script setup> <script setup>
import { inject } from 'vue' import { inject } from 'vue'
import { createResource, Popover, Button } from 'frappe-ui' 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' import { sessionStore } from '@/stores/session'
const dayjs = inject('$dayjs') const dayjs = inject('$dayjs')
@@ -117,16 +128,22 @@ const badges = createResource({
}, },
}) })
const shareOnLinkedIn = (badge) => { const shareOnSocial = (badge, medium) => {
const url = encodeURIComponent(window.location.href) let shareUrl
const image = url.split('/lms')[0] + badge.badge_image const url = encodeURIComponent(
console.log(image) `${window.location.origin}/badges/${badge.badge}/${props.profile.data?.email}`
)
const summary = `I am happy to announce that I earned the ${ const summary = `I am happy to announce that I earned the ${
badge.badge badge.badge
} badge on ${dayjs(badge.issued_on).format('DD MMM YYYY')} at ${ } badge on ${dayjs(badge.issued_on).format('DD MMM YYYY')} at ${
branding.data?.brand_name 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') window.open(shareUrl, '_blank')
} }
</script> </script>

View File

@@ -135,6 +135,12 @@ const routes = [
name: 'Notifications', name: 'Notifications',
component: () => import('@/pages/Notifications.vue'), component: () => import('@/pages/Notifications.vue'),
}, },
{
path: '/badges/:badgeName/:email',
name: 'Badge',
component: () => import('@/pages/Badge.vue'),
props: true,
},
] ]
let router = createRouter({ let router = createRouter({
@@ -154,7 +160,8 @@ router.beforeEach(async (to, from, next) => {
isLoggedIn && isLoggedIn &&
(to.name == 'Lesson' || (to.name == 'Lesson' ||
to.name == 'Batch' || to.name == 'Batch' ||
to.name == 'Notifications') to.name == 'Notifications' ||
to.name == 'Badge')
) { ) {
await allUsers.reload() await allUsers.reload()
} }

View File

@@ -98,7 +98,7 @@
"link_fieldname": "badge" "link_fieldname": "badge"
} }
], ],
"modified": "2024-05-14 14:46:13.644382", "modified": "2024-05-27 17:25:55.399830",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "LMS", "module": "LMS",
"name": "LMS Badge", "name": "LMS Badge",
@@ -116,6 +116,15 @@
"role": "System Manager", "role": "System Manager",
"share": 1, "share": 1,
"write": 1 "write": 1
},
{
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "All",
"share": 1
} }
], ],
"sort_field": "creation", "sort_field": "creation",

View File

@@ -15,10 +15,10 @@
<meta name="twitter:title" content="{{ meta.title }}" /> <meta name="twitter:title" content="{{ meta.title }}" />
<meta name="twitter:image" content="{{ meta.image }}" /> <meta name="twitter:image" content="{{ meta.image }}" />
<meta name="twitter:description" content="{{ meta.description }}" /> <meta name="twitter:description" content="{{ meta.description }}" />
<script type="module" crossorigin src="/assets/lms/frontend/assets/index-DH4LPAyv.js"></script> <script type="module" crossorigin src="/assets/lms/frontend/assets/index-BCIMZEe3.js"></script>
<link rel="modulepreload" crossorigin href="/assets/lms/frontend/assets/frappe-ui-Cdm1MNHD.js"> <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/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> </head>
<body> <body>
<div id="app"> <div id="app">

View File

@@ -130,3 +130,20 @@ def get_meta(app_path):
"keywords": f"{user.full_name}, {user.bio}", "keywords": f"{user.full_name}, {user.bio}",
"link": f"/user/{username}", "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}",
}