feat: category settings
This commit is contained in:
@@ -30,9 +30,11 @@
|
||||
<div class="overflow-y-scroll">
|
||||
<div class="text-base divide-y">
|
||||
<FormControl
|
||||
:value="cat.name"
|
||||
:value="cat.category"
|
||||
type="text"
|
||||
v-for="cat in categories.data"
|
||||
class="py-3"
|
||||
class="form-control"
|
||||
@change.stop="(e) => update(cat.name, e.target.value)"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -44,6 +46,7 @@ import {
|
||||
FormControl,
|
||||
createListResource,
|
||||
createResource,
|
||||
debounce,
|
||||
} from 'frappe-ui'
|
||||
import { Plus, X } from 'lucide-vue-next'
|
||||
import { ref } from 'vue'
|
||||
@@ -99,4 +102,52 @@ const showCategoryForm = () => {
|
||||
categoryInput.value.$el.querySelector('input').focus()
|
||||
}, 0)
|
||||
}
|
||||
|
||||
const updateCategory = createResource({
|
||||
url: 'frappe.client.set_value',
|
||||
makeParams(values) {
|
||||
return {
|
||||
doctype: 'LMS Category',
|
||||
name: values.name,
|
||||
fieldname: {
|
||||
category: values.value,
|
||||
},
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
const update = debounce((name, value) => {
|
||||
updateCategory.submit(
|
||||
{
|
||||
name: name,
|
||||
value: value,
|
||||
},
|
||||
{
|
||||
onSuccess() {
|
||||
categories.reload()
|
||||
},
|
||||
}
|
||||
)
|
||||
}, 500)
|
||||
</script>
|
||||
<style>
|
||||
.form-control input {
|
||||
padding: 1.25rem 0;
|
||||
border-color: transparent;
|
||||
background: white;
|
||||
}
|
||||
|
||||
.form-control input:focus {
|
||||
outline: transparent;
|
||||
background: white;
|
||||
box-shadow: none;
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.form-control input:hover {
|
||||
outline: transparent;
|
||||
background: white;
|
||||
box-shadow: none;
|
||||
border-color: transparent;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<h1 class="mb-3 px-2 pt-2 text-lg font-semibold">
|
||||
{{ __('Settings') }}
|
||||
</h1>
|
||||
<div v-for="tab in tabs">
|
||||
<div v-for="tab in tabs" :key="tab.label">
|
||||
<div
|
||||
v-if="!tab.hideLabel"
|
||||
class="mb-2 mt-3 flex cursor-pointer gap-1.5 px-1 text-base font-medium text-gray-600 transition-all duration-300 ease-in-out"
|
||||
@@ -17,6 +17,7 @@
|
||||
<SidebarLink
|
||||
v-for="item in tab.items"
|
||||
:link="item"
|
||||
:key="item.label"
|
||||
class="w-full"
|
||||
:class="
|
||||
activeTab?.label == item.label
|
||||
@@ -30,6 +31,7 @@
|
||||
</div>
|
||||
<div
|
||||
v-if="activeTab && data.doc"
|
||||
:key="activeTab.label"
|
||||
class="flex flex-1 flex-col px-10 py-8"
|
||||
>
|
||||
<Members
|
||||
@@ -58,14 +60,16 @@
|
||||
<script setup>
|
||||
import { Dialog, createDocumentResource } from 'frappe-ui'
|
||||
import { ref, computed, watch } from 'vue'
|
||||
import { useSettings } from '@/stores/settings'
|
||||
import SettingDetails from '../SettingDetails.vue'
|
||||
import SidebarLink from '@/components/SidebarLink.vue'
|
||||
import Members from '@/components/Members.vue'
|
||||
import Categories from '../Categories.vue'
|
||||
import Categories from '@/components/Categories.vue'
|
||||
|
||||
const show = defineModel()
|
||||
const doctype = ref('LMS Settings')
|
||||
const activeTab = ref(null)
|
||||
const settingsStore = useSettings()
|
||||
|
||||
const data = createDocumentResource({
|
||||
doctype: doctype.value,
|
||||
@@ -75,8 +79,8 @@ const data = createDocumentResource({
|
||||
auto: true,
|
||||
})
|
||||
|
||||
const tabs = computed(() => {
|
||||
let _tabs = [
|
||||
const tabsStructure = computed(() => {
|
||||
return [
|
||||
{
|
||||
label: 'Settings',
|
||||
hideLabel: true,
|
||||
@@ -86,11 +90,23 @@ const tabs = computed(() => {
|
||||
description: 'Manage the members of your learning system',
|
||||
icon: 'UserRoundPlus',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Settings',
|
||||
hideLabel: true,
|
||||
items: [
|
||||
{
|
||||
label: 'Categories',
|
||||
description: 'Manage the members of your learning system',
|
||||
icon: 'Network',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Settings',
|
||||
hideLabel: true,
|
||||
items: [
|
||||
{
|
||||
label: 'Payment Gateway',
|
||||
icon: 'DollarSign',
|
||||
@@ -136,8 +152,8 @@ const tabs = computed(() => {
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Settings',
|
||||
hideLabel: true,
|
||||
label: 'Customise',
|
||||
hideLabel: false,
|
||||
items: [
|
||||
{
|
||||
label: 'Sidebar',
|
||||
@@ -179,12 +195,6 @@ const tabs = computed(() => {
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Settings',
|
||||
hideLabel: true,
|
||||
items: [
|
||||
{
|
||||
label: 'Email Templates',
|
||||
icon: 'MailPlus',
|
||||
@@ -210,12 +220,6 @@ const tabs = computed(() => {
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: 'Settings',
|
||||
hideLabel: true,
|
||||
items: [
|
||||
{
|
||||
label: 'Signup',
|
||||
icon: 'LogIn',
|
||||
@@ -268,23 +272,36 @@ const tabs = computed(() => {
|
||||
],
|
||||
},
|
||||
]
|
||||
})
|
||||
|
||||
return _tabs.map((tab) => {
|
||||
tab.items = tab.items.filter((item) => {
|
||||
if (item.condition) {
|
||||
return item.condition()
|
||||
}
|
||||
return true
|
||||
})
|
||||
return tab
|
||||
const tabs = computed(() => {
|
||||
return tabsStructure.value.map((tab) => {
|
||||
return {
|
||||
...tab,
|
||||
items: tab.items.filter((item) => {
|
||||
return !item.condition || item.condition()
|
||||
}),
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
watch(show, () => {
|
||||
watch(
|
||||
() => activeTab.value,
|
||||
(value) => {
|
||||
console.log('Tab watcher', value)
|
||||
}
|
||||
)
|
||||
|
||||
watch(show, async () => {
|
||||
if (show.value) {
|
||||
activeTab.value = tabs.value[0].items[0]
|
||||
const currentTab = await tabs.value
|
||||
.flatMap((tab) => tab.items)
|
||||
.find((item) => item.label === settingsStore.activeTab)
|
||||
activeTab.value = currentTab || tabs.value[0].items[0]
|
||||
} else {
|
||||
console.log('else')
|
||||
activeTab.value = null
|
||||
settingsStore.isSettingsOpen = false
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -67,25 +67,20 @@ import LMSLogo from '@/components/Icons/LMSLogo.vue'
|
||||
import { sessionStore } from '@/stores/session'
|
||||
import { Dropdown } from 'frappe-ui'
|
||||
import Apps from '@/components/Apps.vue'
|
||||
import {
|
||||
ChevronDown,
|
||||
LogIn,
|
||||
LogOut,
|
||||
User,
|
||||
ArrowRightLeft,
|
||||
Settings,
|
||||
} from 'lucide-vue-next'
|
||||
import { ChevronDown, LogIn, LogOut, User, Settings } from 'lucide-vue-next'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { convertToTitleCase } from '../utils'
|
||||
import { usersStore } from '@/stores/user'
|
||||
import { ref, markRaw } from 'vue'
|
||||
import { useSettings } from '@/stores/settings'
|
||||
import { markRaw, watch, ref } from 'vue'
|
||||
import SettingsModal from '@/components/Modals/Settings.vue'
|
||||
|
||||
const router = useRouter()
|
||||
const showSettingsModal = ref(false)
|
||||
const { logout, branding } = sessionStore()
|
||||
let { userResource } = usersStore()
|
||||
const settingsStore = useSettings()
|
||||
let { isLoggedIn } = sessionStore()
|
||||
const showSettingsModal = ref(false)
|
||||
|
||||
const props = defineProps({
|
||||
isCollapsed: {
|
||||
@@ -94,6 +89,13 @@ const props = defineProps({
|
||||
},
|
||||
})
|
||||
|
||||
watch(
|
||||
() => settingsStore.isSettingsOpen,
|
||||
(value) => {
|
||||
showSettingsModal.value = value
|
||||
}
|
||||
)
|
||||
|
||||
const userDropdownOptions = [
|
||||
{
|
||||
icon: User,
|
||||
@@ -118,7 +120,7 @@ const userDropdownOptions = [
|
||||
icon: Settings,
|
||||
label: 'Settings',
|
||||
onClick: () => {
|
||||
showSettingsModal.value = true
|
||||
settingsStore.isSettingsOpen = true
|
||||
},
|
||||
condition: () => {
|
||||
return userResource.data?.is_moderator
|
||||
|
||||
Reference in New Issue
Block a user