Review App Using Laravel 11 & Vue js 3 Composition API Part 5

2 months ago admin Vuejs

In the last part of this tutorial, we will display the reviews list of each product, add the ability to add/update reviews, and remove reviews.


Add the reviews list component

Inside the reviews list component, we display all the reviews with buttons to edit and delete a selected review.

                                                        
                                                                                                                        
<template>
  <div class="card mb-2">
    <div class="card-header bg-white">
        <h5 class="text-center mt-2">
            Reviews ({{ props.reviews.length }})
        </h5>
    </div>
    <div class="card-body">
        <ul class="mt-4 list-group">
            <li class="list-group-item d-flex justify-content-between align-items-start"
                v-for="review in props.reviews"
                :key="review.id"
                >
                <div class="ms-2 me-auto">
                    <div class="fw-bold">
                        {{ review.title }}
                    </div>
                    <p>
                        {{ review.body }}
                    </p>
                    <p class="cart-text">
                        <small class="text-body-seconda">
                            by {{ review.user.name }} - <span class="text-danger">{{ review.created_at }}</span>
                        </small>
                    </p>
                    <p>
                        <StarRating 
                            v-model:rating="review.rating"
                            :show-rating="false"
                            read-only
                            :star-size="24"
                        />
                    </p>
                </div>
                <div class="d-flex flex-column align-items-center">
                    <button class="btn btn-sm btn-danger mb-2"
                        @click="removeReview(review)">
                        <i class="bi bi-trash"></i>
                    </button>
                    <button class="btn btn-sm btn-warning mb-2"
                        @click="editReview(review)">
                        <i class="bi bi-pencil"></i>
                    </button>
                </div>
            </li>
        </ul>
    </div>
  </div>
</template>

<script setup>
    import StarRating from 'vue-star-rating'

    const props = defineProps({
        reviews: {
            type: Array,
            required: true
        }
    })

    const emit = defineEmits(['editReviewEvent', 'removeReviewEvent'])

    const editReview = (review) => {
        emit('editReviewEvent', review)
    }

    const removeReview = (review) => {
        emit('removeReviewEvent', review.id)
    }
</script>

<style>

</style>

Add the add review component

Inside, the add review component we have the form to review a selected product.

                                                            
                                                                                                                                
<template>
    <form class="mt-5">
        <div class="mb-3">
            <label for="title">Title*</label>
            <input type="text" name="title" id="title"
                v-model="data.review.title"
                class="form-control"
                placeholder="Title">
        </div>
        <div class="mb-3">
            <label for="body">Body*</label>
            <textarea 
                rows="3"
                cols="30"
                name="body" id="body"
                v-model="data.review.body"
                class="form-control"
                placeholder="Body"></textarea>
        </div>
        <div class="mb-3">
            <StarRating 
                v-model:rating="data.review.rating"
                :show-rating="false"
            />
        </div>
        <div class="mb-3">
            <button class="btn btn-dark"
                :disabled="disabled"
                @click.prevent="storeReview">
                Submit
            </button>
        </div>
    </form>
</template>

<script setup>
    import { computed, reactive } from 'vue'
    import StarRating from 'vue-star-rating'
    import axios from "axios"
    import { useToast } from 'vue-toastification'

    const toast = useToast()

    const data = reactive({
        review: {
            title: '',
            body: '',
            rating: 0
        }
    })

    const props = defineProps({
        product: {
            type: Object,
            required: true
        }
    })

    const emit = defineEmits(['reviewAdded'])

    const disabled = computed(() => {
        if(!data.review.title || !data.review.body || data.review.rating === 0){
            return true
        }else {
            false
        }
    })

    const storeReview = async () => {
        try {
            const response = await axios.post(`https://darija-coding.com/api/review/${props.product.id}/store`,
                {
                    title: data.review.title,
                    body: data.review.body,
                    rating: data.review.rating,
                    user_id: Math.floor(Math.random() * 10) + 1 
                    //generate a random user id between 1 and 10
                }
            )
            data.review = {
                title: '',
                body: '',
                rating: 0
            }

            emit('reviewAdded', response.data.data)

            toast.success('Review has been added successfully', {
                timeout: 2000
            })

        } catch (error) {
            console.log(error)
        }
    }
</script>

<style>

</style>

Add the update review component

Inside, the update review component we have the form to update a selected review.

                                                            
                                                                                                                                
<template>
    <form class="mt-5">
        <div class="mb-3">
            <label for="title">Title*</label>
            <input type="text" name="title" id="title"
                v-model="data.review.title"
                class="form-control"
                placeholder="Title">
        </div>
        <div class="mb-3">
            <label for="body">Body*</label>
            <textarea 
                rows="3"
                cols="30"
                name="body" id="body"
                v-model="data.review.body"
                class="form-control"
                placeholder="Body"></textarea>
        </div>
        <div class="mb-3">
            <StarRating 
                v-model:rating="data.review.rating"
                :show-rating="false"
            />
        </div>
        <div class="mb-3">
            <button class="btn btn-warning"
                :disabled="disabled"
                @click.prevent="updateReview">
                Update
            </button>
            <button class="btn btn-primary mx-2"
                @click.prevent="cancelUpdate">
                Cancel
            </button>
        </div>
    </form>
</template>

<script setup>
    import { computed, onMounted, reactive } from 'vue'
    import StarRating from 'vue-star-rating'
    import axios from "axios"
    import { useToast } from 'vue-toastification'

    const toast = useToast()

    const data = reactive({
        review: {
            title: '',
            body: '',
            rating: 0
        }
    })

    const props = defineProps({
        reviewToUpdate: {
            type: Object,
            required: true
        },
        product: {
            type: Object,
            required: true
        }
    })

    const emit = defineEmits(['reviewUpdated', 'cancelUpdating'])

    const disabled = computed(() => {
        if(!data.review.title || !data.review.body || data.review.rating === 0){
            return true
        }else {
            false
        }
    })

    const updateReview = async () => {
        try {
            const response = await axios.put(`https://darija-coding.com/api/review/${props.product.id}/${data.review.id}/update`,
                {
                    title: data.review.title,
                    body: data.review.body,
                    rating: data.review.rating,
                    user_id: Math.floor(Math.random() * 10) + 1 
                    //generate a random user id between 1 and 10
                }
            )
            data.review = {
                title: '',
                body: '',
                rating: 0
            }

            emit('reviewUpdated', response.data.data)

            toast.success('Review has been updated successfully', {
                timeout: 2000
            })

        } catch (error) {
            console.log(error)
        }
    }
    
    const cancelUpdate = () => {
        emit('cancelUpdating')
    }

    onMounted(() => data.review = props.reviewToUpdate)
</script>

<style>

</style>

Popular Tutorials

Related Tutorials

Review App Using Laravel 11 & Vue js 3 Composition API Part 4

In the fourth part of this tutorial, we will fetch and display all the products on the home page, vi...


Review App Using Laravel 11 & Vue js 3 Composition API Part 3

In the third part of this tutorial, we will start coding the front end, first, we will install the p...


Review App Using Laravel 11 & Vue js 3 Composition API Part 2

In the second part of this tutorial, we will create the product and review controllers, and later we...


Review App Using Laravel 11 & Vue js 3 Composition API Part 1

In this tutorial, we will create a review app using Laravel 11 & Vue js 3 Composition API, the user...


Build a Shopping Cart Using Vue js 3 Composition API Laravel 11 & Stripe Payment Gateway Part 5

In the final part of this tutorial, we will display the cart items, add the ability to increment/dec...


Build a Shopping Cart Using Vue js 3 Composition API Laravel 11 & Stripe Payment Gateway Part 4

In the fourth part of this tutorial, we will fetch and display all the products, and add the store w...


Build a Shopping Cart Using Vue js 3 Composition API Laravel 11 & Stripe Payment Gateway Part 3

In the third part of this tutorial, we will move to the front end, we will install the packages...


Build a Shopping Cart Using Vue js 3 Composition API Laravel 11 & Stripe Payment Gateway Part 2

In the second part of this tutorial, we will create the product and order controllers, add the...


Build a Shopping Cart Using Vue js 3 Composition API Laravel 11 & Stripe Payment Gateway Part 1

In this tutorial, we will create a shopping cart using vue js 3 composition API Laravel 11 and strip...


How to Get URL Query Params in Vue 3 Composition API

In this lesson, we will see how to get URL query params in Vue 3 composition API, let's assume that...