Skip to content
Open
57 changes: 37 additions & 20 deletions app/components/common/gomboBox.vue
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ interface IGomboBox {
hasMoreItems?: boolean
height?: string | number
titleModal?: string
findByTitle?: boolean
}

const props = withDefaults(defineProps<IGomboBox>(), {
Expand All @@ -120,6 +121,7 @@ const props = withDefaults(defineProps<IGomboBox>(), {
loadingMore: false,
hasMoreItems: true,
titleModal: '',
findByTitle: false,
})

const emit = defineEmits(['update:modelValue', 'loadMore'])
Expand All @@ -129,11 +131,20 @@ const inputText = ref('')
const dense = ref(false)
const selectedItem = ref<IItemGomboBox | null>(null)

const isSameValue = (firstValue: unknown, secondValue: unknown) => {
return firstValue == Number(secondValue) || firstValue == secondValue
}

const findSelectedItem = (value?: string | number) => {
return props.items.find((item) => {
const selectedValue = item[props.itemValue]
const selectedTitle = item[props.itemTitle]

return selectedValue == Number(value) || selectedValue == value
if (props.findByTitle && isSameValue(selectedTitle, value)) {
return true
}

return isSameValue(selectedValue, value)
})
}

Expand All @@ -143,34 +154,44 @@ const getItemText = (item: IItemGomboBox, key: string) => {
return value == null ? '' : String(value)
}

const syncSelectedItem = (value?: string | number) => {
if (props.items.length === 0) {
inputText.value = ''
selectedItem.value = null
return
}

const foundObj = findSelectedItem(value)
selectedItem.value = foundObj || null
inputText.value = foundObj ? getItemText(foundObj, props.itemTitle) : ''

if (props.findByTitle && value && !foundObj) {
emit('update:modelValue', '')
return
}

if (props.findByTitle && foundObj && !isSameValue(foundObj.id, value)) {
emit('update:modelValue', String(foundObj.id))
}
}

watch(
() => props.items,
(newValue) => {
if (newValue.length > 0) {
const foundObj = findSelectedItem(props.modelValue)
if (foundObj) {
inputText.value = getItemText(foundObj, props.itemTitle)
selectedItem.value = foundObj
}
else inputText.value = ''
syncSelectedItem(props.modelValue)
}
else {
inputText.value = ''
selectedItem.value = null
}
},
)

watch(
() => props.modelValue,
(newValue) => {
if (props.items.length > 0) {
const foundObj = findSelectedItem(newValue)
selectedItem.value = foundObj ? foundObj : null
inputText.value = foundObj ? getItemText(foundObj, props.itemTitle) : ''
}
else {
inputText.value = ''
}
syncSelectedItem(newValue)
},
)

Expand All @@ -191,11 +212,7 @@ const setValue = (item: IItemGomboBox) => {
}

onMounted(() => {
if (props.items.length > 0) {
const foundObj = findSelectedItem(props.modelValue)
selectedItem.value = foundObj ? foundObj : null
inputText.value = foundObj ? getItemText(foundObj, props.itemTitle) : ''
}
syncSelectedItem(props.modelValue)
})
</script>

Expand Down
2 changes: 1 addition & 1 deletion app/components/common/modal/base.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
@click="clickOnOverlay"
>
<div
class="w-100 d-flex flex-column bg-white pa-6 rounded-xl overflow-y-auto mobile-style"
class="w-100 d-flex flex-column bg-white rounded-xl overflow-y-auto mobile-style py-6 px-3 px-sm-6"
@click="clickOnModal"
>
<div class="w-100 d-flex align-center justify-space-between">
Expand Down
40 changes: 15 additions & 25 deletions app/components/menu/AddOptionBottomMenu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
:key="item.title"
:to="item.path"
:aria-label="`${item.title} — ${item.typeFile}`"
class="card-add-option d-flex flex-column align-center justify-center text-center ga-1 rounded-xl"
class="card-add-option d-flex flex-column align-center justify-start text-center ga-1 rounded-xl py-4"
>
<div class="icon-div rounded-lg pa-2 d-flex align-center justify-center bg-primary100">
<span
Expand All @@ -22,7 +22,7 @@
{{ item.iconMd }}
</v-icon>
</div>
<span class="card-option-title w-100 text-center text-grey700 text-h6 font-weight-bold mt-1">{{ item.title }}</span>
<span class="card-option-title w-100 text-center text-grey700 text-h6 px-1 font-weight-bold mt-1">{{ item.title }}</span>

<span class="text-center text-subtitle-2 font-weight-bold text-grey500 px-2 rounded-pill bg-grey100 chip-type-file">
{{ item.typeFile }}
Expand Down Expand Up @@ -59,39 +59,43 @@ interface AddOption {
iconMd?: string
}

const addOptions: AddOption[] = [
const { user } = useUser()
const defaultBoardId = 6627
const userBoardId = computed(() => user.value?.board || defaultBoardId)

const addOptions = computed<AddOption[]>(() => [
{
path: '/user/paper/create',
path: `/user/paper/create?board=${userBoardId.value}&classification=310`,
title: 'Worksheet',
iconMd: 'md:description_outlined',
typeFile: 'PDF · DOCX',
},
{
path: '/user/paper/create',
path: `/user/paper/create?board=${userBoardId.value}&classification=8344`,
title: 'Predicted Paper',
icon: 'icon-paper',
typeFile: 'PDF · DOCX',
},
{
path: '/user/paper/create',
path: `/user/paper/create?board=${userBoardId.value}&classification=6896`,
title: 'Study Guide',
iconMd: 'md:menu_book',
typeFile: 'PDF · DOCX',
},
{
path: '/user/paper/create',
path: `/user/paper/create?board=${userBoardId.value}&classification=7180`,
title: 'Topical Questions',
iconMd: 'md:quiz_outlined',
typeFile: 'PDF · DOCX',
},
{
path: '/user/multimedia/create',
path: '/user/multimedia/create?contentType=6022',
title: 'Video',
iconMd: 'md:videocam',
typeFile: 'MP4',
},
{
path: '/user/multimedia/create',
path: '/user/multimedia/create?contentType=6024',
title: 'Presentation',
iconMd: 'md:slideshow',
typeFile: 'PPTX',
Expand All @@ -114,7 +118,7 @@ const addOptions: AddOption[] = [
iconMd: 'md:art_track',
typeFile: 'HTML',
},
]
])

watch(
() => route.fullPath,
Expand All @@ -129,10 +133,8 @@ watch(
max-width : 370px
}
.card-add-option{
width : 30%;
width : 31%;
max-width : 120px;
height : 112px;
padding-top: 8px;
border : 1px solid rgb(var(--v-theme-grey200));
transition: 0.3s;
text-decoration: none;
Expand All @@ -152,14 +154,6 @@ watch(
border : 1px solid rgb(var(--v-theme-primary100))
}

@media only screen and (max-width: 599.98px) {
.card-option-title {
padding-inline: 8px;
font-size: calc(1.25rem - 1px) !important;
line-height: 1.25rem;
}
}

@media only screen and (min-width: 960px) {
.container-card {
max-width: 480px;
Expand All @@ -168,9 +162,5 @@ watch(
.card-add-option {
max-width: 144px;
}

.card-option-title {
padding-inline: 8px;
}
}
</style>
27 changes: 26 additions & 1 deletion app/pages/user/multimedia/create.vue
Original file line number Diff line number Diff line change
Expand Up @@ -318,10 +318,11 @@ const { uploadFile, loadingUploadFile } = useUpload()
const { addItem, loadingAddItem } = useMultimedia()
const { $toast } = useNuxtApp()
const router = useRouter()
const route = useRoute()

const isFormValid = ref(false)
const multimediaFile = ref<File | File[] | null>(null)
const multimedia = ref<MultimediaForm>({
const createDefaultMultimedia = (): MultimediaForm => ({
board: '',
grade: '',
subject: '',
Expand All @@ -334,6 +335,7 @@ const multimedia = ref<MultimediaForm>({
free_available: false,
file: '',
})
const multimedia = ref<MultimediaForm>(createDefaultMultimedia())

const getSelectedFile = (value: unknown) => {
if (value instanceof File) return value
Expand Down Expand Up @@ -409,12 +411,35 @@ const submitMultimedia = async () => {
}
}

const applyQueryDefaults = async () => {
if (route.query.contentType) {
multimedia.value.content_type = route.query.contentType as string
}
}

const resetFormState = () => {
multimedia.value = createDefaultMultimedia()
multimediaFile.value = null
resetGrades()
resetSubjects()
resetTopics()
}

onMounted(async () => {
await Promise.all([
getBoards(),
getExtraTypeFile('content_type'),
])
await applyQueryDefaults()
})

watch(
() => route.query,
async () => {
resetFormState()
await applyQueryDefaults()
},
)
</script>

<style scoped>
Expand Down
41 changes: 38 additions & 3 deletions app/pages/user/paper/create.vue
Original file line number Diff line number Diff line change
Expand Up @@ -546,9 +546,10 @@ const { $toast } = useNuxtApp()
const { addItem,
loadingAddItem } = usePastPaper()
const router = useRouter()
const route = useRoute()

const isFormValid = ref(false)
const paper = ref<PaperForm>({
const createDefaultPaper = (): PaperForm => ({
board: '',
grade: '',
subject: '',
Expand All @@ -568,6 +569,7 @@ const paper = ref<PaperForm>({
area: '',
school: '',
})
const paper = ref<PaperForm>(createDefaultPaper())
const pdfQuestionFile = ref(null)
const pdfSolutionFile = ref(null)
const wordQuestionAndSolutionFile = ref(null)
Expand Down Expand Up @@ -767,6 +769,30 @@ const subjectChange = async (subjectId: number | string) => {
}
}

const resetFormState = () => {
paper.value = createDefaultPaper()
pdfQuestionFile.value = null
pdfSolutionFile.value = null
wordQuestionAndSolutionFile.value = null
extraFileList.value = []
uploadingFileKeys.value = []
resetGrades()
resetSubjects()
resetClassifications()
resetTopics()
}

const applyQueryDefaults = async () => {
if (route.query.board) {
paper.value.board = route.query.board as string
await getGrades(paper.value.board)
await getClassification(paper.value.board)
if (route.query.classification) {
paper.value.classification = route.query.classification as string
}
}
}

const submitPaper = async () => {
const response = await addItem({
...paper.value,
Expand All @@ -784,9 +810,18 @@ const submitPaper = async () => {
}

onMounted(async () => {
await getBoards()
await getExtraTypeFile('test_extra_file')
getBoards()
getExtraTypeFile('test_extra_file')
await applyQueryDefaults()
})

watch(
() => route.query,
async () => {
resetFormState()
await applyQueryDefaults()
},
)
</script>

<style scoped>
Expand Down
2 changes: 1 addition & 1 deletion app/pages/user/paper/edit/[id]/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@
<div class="each-item d-flex flex-column align-start justify-start ga-1 mt-4">
<common-gombo-box
v-model="paper.classification"
label="Subject"
label="Classification"
:items="classifications?.map((item) => {
return {
id: item.id,
Expand Down