-
Notifications
You must be signed in to change notification settings - Fork 4.1k
WIP - Add Free/Sales-Call/Paid badges to Modules #7738
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e16b4a7
df4b636
ff9ec1e
6d783ee
4ba683d
ea431cb
a77421f
b2aa030
49d9c1b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,4 +2,8 @@ | |
|
||
.sb-show-main, .sb-story { | ||
@extend %frontend-page; | ||
} | ||
|
||
.tooltip { | ||
opacity: 1 !important; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import AccessLevelIndicator from './AccessLevelIndicator.vue' | ||
|
||
export default { | ||
title: 'AccessLevelIndicator', | ||
component: AccessLevelIndicator, | ||
argTypes: { | ||
level: { | ||
control: { type: 'select', options: ['free', 'sales-call', 'paid'] }, | ||
description: 'The access level of the user', | ||
}, | ||
displayText: { | ||
control: 'boolean', | ||
description: 'Whether to display the text or not', | ||
}, | ||
displayIcon: { | ||
control: 'boolean', | ||
description: 'Whether to display the icon or not', | ||
}, | ||
}, | ||
} | ||
|
||
const Template = (args, { argTypes }) => ({ | ||
props: Object.keys(argTypes), | ||
components: { AccessLevelIndicator }, | ||
template: '<access-level-indicator v-bind="$props" />', | ||
}) | ||
|
||
export const Free = Template.bind({}) | ||
Free.args = { | ||
level: 'free', | ||
displayText: true, | ||
displayIcon: false, | ||
} | ||
|
||
export const SalesCall = Template.bind({}) | ||
SalesCall.args = { | ||
level: 'sales-call', | ||
displayText: false, | ||
displayIcon: true, | ||
} | ||
|
||
export const Paid = Template.bind({}) | ||
Paid.args = { | ||
level: 'paid', | ||
displayText: true, | ||
displayIcon: true, | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
<template> | ||
<span | ||
v-if="isDisplayable" | ||
v-tooltip.bottom="{ | ||
content: $t(`paywall.badge_tooltip_${level}`), | ||
}" | ||
:class="badgeClass" | ||
> | ||
<span v-if="displayIcon">{{ icon }}</span> | ||
<span v-if="displayText">{{ $t(`paywall.badge_${level}`) }}</span> | ||
</span> | ||
</template> | ||
|
||
<script> | ||
import { mapGetters, mapActions } from 'vuex' | ||
import CourseSchema from 'app/schemas/models/course.schema' | ||
const ACCESS_LEVELS = CourseSchema.properties.modules.additionalProperties.properties.access.enum | ||
|
||
export default { | ||
name: 'AccessLevelIndicator', | ||
props: { | ||
level: { | ||
type: String, | ||
required: false, | ||
validator: value => ACCESS_LEVELS.includes(value), | ||
default: 'free', | ||
}, | ||
displayText: { | ||
type: Boolean, | ||
default: true, | ||
}, | ||
displayIcon: { | ||
type: Boolean, | ||
default: true, | ||
}, | ||
}, | ||
computed: { | ||
...mapGetters({ | ||
isPaidTeacher: 'me/isPaidTeacher', | ||
}), | ||
isDisplayable () { | ||
const userDisplayMap = { | ||
free: ['free', 'sales-call'], // non-paying users will see the 'free' and 'sales-call' badges | ||
'sales-call': ['paid'], // users after sales call will see the 'paid' badges | ||
paid: [], // I'm not sure if we'll have this for users, but if we'll have no badges needed. | ||
} | ||
const userLevel = this.isPaidTeacher ? 'paid' : 'free' | ||
return userDisplayMap[userLevel].includes(this.level) | ||
}, | ||
badgeClass () { | ||
return { | ||
badge: true, | ||
[`badge-${this.level}`]: true, | ||
} | ||
}, | ||
icon () { | ||
const icons = 5D32 { | ||
free: '✨', | ||
'sales-call': '📞', | ||
paid: '🔒', | ||
} | ||
return icons[this.level] || '' | ||
Comment on lines
+58
to
+62
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Use consistent icons instead of emojis Using emojis for icons may lead to inconsistent rendering across different platforms and devices. It's better to use consistent icon components or SVGs that align with the application's design system. Consider importing and using icon components from your UI library. For example: +import FreeIcon from 'components/icons/FreeIcon.vue'
+import SalesCallIcon from 'components/icons/SalesCallIcon.vue'
+import PaidIcon from 'components/icons/PaidIcon.vue'
// In computed property
icon () {
- const icons = {
- free: '✨',
- 'sales-call': '📞',
- paid: '🔒',
+ const icons = {
+ free: FreeIcon,
+ 'sales-call': SalesCallIcon,
+ paid: PaidIcon,
}
return icons[this.level] || ''
}, And update the template to use the icon components: <span v-if="displayIcon">
- {{ icon }}
+ <component :is="icon" />
</span>
|
||
}, | ||
Comment on lines
+56
to
+63
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Consider using consistent icons instead of emojis Using emojis for icons may lead to inconsistent rendering across different platforms and devices. It's better to use consistent icon components or SVGs that align with the application's design system. Consider importing and using icon components from your UI library. For example: import FreeIcon from 'components/icons/FreeIcon.vue'
import SalesCallIcon from 'components/icons/SalesCallIcon.vue'
import PaidIcon from 'components/icons/PaidIcon.vue'
// In computed property
icon() {
const icons = {
free: FreeIcon,
'sales-call': SalesCallIcon,
paid: PaidIcon,
}
return icons[this.level] || null
}, Then update the template to use the icon components: <component :is="icon" v-if="displayIcon && icon" /> This approach ensures consistent rendering across all platforms and devices. |
||
}, | ||
async created () { | ||
await this.ensurePrepaidsLoadedForTeacher(me.get('_id')) | ||
}, | ||
methods: { | ||
...mapActions({ | ||
ensurePrepaidsLoadedForTeacher: 'prepaids/ensurePrepaidsLoadedForTeacher', | ||
}), | ||
}, | ||
} | ||
</script> | ||
|
||
<style scoped lang="scss"> | ||
.badge { | ||
padding: 5px; | ||
border-radius: 3px; | ||
color: white; | ||
font-size: 12px; | ||
} | ||
|
||
.badge-free { | ||
background-color: green; | ||
} | ||
|
||
.badge-sales-call { | ||
background-color: orange; | ||
} | ||
|
||
.badge-paid { | ||
background-color: red; | ||
} | ||
</style> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
<script> | ||
export default { | ||
props: { | ||
content: { | ||
type: String, | ||
required: true, | ||
}, | ||
}, | ||
render (h) { | ||
return h('span', { domProps: { innerHTML: this.content.replace(/`(.*?)`/g, '<code>$1</code>') } }) | ||
}, | ||
} | ||
</script> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Consider using ES6 import syntax for consistency with modern practices.
While the use of
require
is consistent with other imports in this file, consider using ES6 import syntax for better alignment with modern JavaScript practices. Also, the empty line after the import can be removed.Here's a suggested change:
📝 Committable suggestion