feat: review submission
This commit is contained in:
@@ -2,10 +2,12 @@
|
||||
<DesktopLayout>
|
||||
<router-view />
|
||||
</DesktopLayout>
|
||||
<Dialogs />
|
||||
<Toasts />
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import DesktopLayout from '@/components/DesktopLayout.vue'
|
||||
import { Toasts } from 'frappe-ui'
|
||||
import { Dialogs } from '@/utils/dialogs'
|
||||
</script>
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
<div class="mb-2">
|
||||
{{ reviews.data.length }} {{ __("reviews") }}
|
||||
</div>
|
||||
<Button @click="openReviewModal()">
|
||||
<Button v-if="membership" @click="openReviewModal()">
|
||||
<span>
|
||||
{{ __("Write a review") }}
|
||||
</span>
|
||||
@@ -62,7 +62,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ReviewModal v-model="showReviewModal" v-model:reloadReviews="reviews"/>
|
||||
<ReviewModal v-model="showReviewModal" v-model:reloadReviews="reviews" :courseName="courseName"/>
|
||||
</template>
|
||||
<script setup>
|
||||
import { Star } from 'lucide-vue-next'
|
||||
@@ -80,6 +80,10 @@ const props = defineProps({
|
||||
type: Number,
|
||||
required: true,
|
||||
},
|
||||
membership: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -94,7 +98,7 @@ const reviews = createResource({
|
||||
},
|
||||
auto: true,
|
||||
});
|
||||
|
||||
console.log(reviews)
|
||||
const rating_percent = computed(() => {
|
||||
let rating_count = {};
|
||||
let rating_percent = {};
|
||||
|
||||
@@ -16,7 +16,7 @@ const props = defineProps({
|
||||
default: '',
|
||||
},
|
||||
modelValue: {
|
||||
type: String,
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
{
|
||||
label: "Submit",
|
||||
variant: "solid",
|
||||
onClick: ({ close }) => submitReview(close)
|
||||
onClick: (close) => submitReview(close)
|
||||
}
|
||||
]
|
||||
}'>
|
||||
@@ -30,12 +30,23 @@
|
||||
</template>
|
||||
<script setup>
|
||||
import { Dialog, Textarea, createResource } from 'frappe-ui'
|
||||
import { defineModel, ref } from "vue"
|
||||
import { defineModel, reactive } from "vue"
|
||||
import Rating from '@/components/Rating.vue';
|
||||
import { createToast } from "@/utils/"
|
||||
|
||||
const show = defineModel()
|
||||
const reviews = defineModel("reloadReviews")
|
||||
let review = ref({})
|
||||
let review = reactive({
|
||||
review: "",
|
||||
rating: 0,
|
||||
})
|
||||
|
||||
const props = defineProps({
|
||||
courseName: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
})
|
||||
|
||||
const createReview = createResource({
|
||||
url: "frappe.client.insert",
|
||||
@@ -43,22 +54,28 @@ const createReview = createResource({
|
||||
return {
|
||||
doc: {
|
||||
doctype: "LMS Course Review",
|
||||
course: props.courseName,
|
||||
...values,
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
function submitReview(close) {
|
||||
review.rating = (review.rating)/5;
|
||||
createReview.submit(review, {
|
||||
validate() {
|
||||
/* if (!review.value.rating) {
|
||||
return __("Please select a rating")
|
||||
if (!review.rating) {
|
||||
return "Please enter a rating."
|
||||
}
|
||||
if (!review.value.review) {
|
||||
return __("Please write a review")
|
||||
} */
|
||||
}, onSuccess() {
|
||||
reviews.reload()
|
||||
reviews.value.reload()
|
||||
},
|
||||
onError(err) {
|
||||
createToast({
|
||||
text: err.messages?.[0] || err,
|
||||
icon: 'x',
|
||||
iconClasses: 'text-red-600 bg-red-300',
|
||||
})
|
||||
}
|
||||
})
|
||||
close();
|
||||
|
||||
@@ -54,7 +54,7 @@
|
||||
</div>
|
||||
<CourseOutline :courseName="course.data.name"/>
|
||||
</div>
|
||||
<CourseReviews v-if="course.data.avg_rating" :courseName="course.data.name" :avg_rating="course.data.avg_rating"/>
|
||||
<CourseReviews v-if="course.data.avg_rating" :courseName="course.data.name" :avg_rating="course.data.avg_rating" :membership="course.data.membership"/>
|
||||
</div>
|
||||
<div>
|
||||
<CourseCardOverlay :course="course"/>
|
||||
|
||||
@@ -5,9 +5,10 @@
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"review",
|
||||
"rating",
|
||||
"course"
|
||||
"course",
|
||||
"column_break_lrtk",
|
||||
"review"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
@@ -20,7 +21,8 @@
|
||||
"fieldname": "rating",
|
||||
"fieldtype": "Rating",
|
||||
"in_list_view": 1,
|
||||
"label": "Rating"
|
||||
"label": "Rating",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "course",
|
||||
@@ -28,12 +30,17 @@
|
||||
"in_list_view": 1,
|
||||
"in_standard_filter": 1,
|
||||
"label": "Course",
|
||||
"options": "LMS Course"
|
||||
"options": "LMS Course",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_lrtk",
|
||||
"fieldtype": "Column Break"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2021-11-16 17:23:50.697891",
|
||||
"modified": "2023-12-21 15:25:16.744558",
|
||||
"modified_by": "Administrator",
|
||||
"module": "LMS",
|
||||
"name": "LMS Course Review",
|
||||
@@ -50,11 +57,24 @@
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"export": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "LMS Student",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"search_fields": "course",
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"title_field": "course",
|
||||
"track_changes": 1
|
||||
}
|
||||
@@ -7,7 +7,14 @@ from frappe.utils import cint
|
||||
|
||||
|
||||
class LMSCourseReview(Document):
|
||||
pass
|
||||
def validate(self):
|
||||
self.validate_if_already_reviewed()
|
||||
|
||||
def validate_if_already_reviewed(self):
|
||||
if frappe.db.exists(
|
||||
"LMS Course Review", {"course": self.course, "owner": self.owner}
|
||||
):
|
||||
frappe.throw(frappe._("You have already reviewed this course"))
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
|
||||
Reference in New Issue
Block a user