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

3 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>

Related Tuorials

How to Persist Data in the Pinia Store

In this lesson, we will see how to persist data in the Pinia store.When working with Pinia...


How to Reset the File input Field in Vue js

In this lesson, we will see how to reset the file input field in Vue js.When uploading files using V...


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...