Skip to content

Commit

Permalink
Offer functionallity
Browse files Browse the repository at this point in the history
  • Loading branch information
szmmon committed May 9, 2024
1 parent 7e5eb1a commit fbb5ed1
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 7 deletions.
26 changes: 26 additions & 0 deletions app/Http/Controllers/ListingOfferController.php
Original file line number Diff line number Diff line change
@@ -0,0 1,26 @@
<?php

namespace App\Http\Controllers;

use App\Models\Offer;
use App\Models\Listing;
use Illuminate\Http\Request;

class ListingOfferController extends Controller
{
public function store(Listing $listing, Request $request)
{
$listing->offers()->save(
Offer::make(
$request->validate([
'amount' => 'required|integer|min:1|max:20000000'
])
)->bidder()->associate($request->user())
);

return redirect()->back()->with(
'success',
'Offer was made!'
);
}
}
4 changes: 4 additions & 0 deletions app/Models/Listing.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 67,10 @@ public function images():HasMany{
return $this->hasMany(ListingImage::class);
}

public function offers():HasMany{
return $this->hasMany(Offer::class, 'listing_id');
}


use HasFactory, SoftDeletes;

Expand Down
26 changes: 26 additions & 0 deletions app/Models/Offer.php
Original file line number Diff line number Diff line change
@@ -0,0 1,26 @@
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Offer extends Model
{

protected $fillable = [
'amount',
'accepted_at',
'rejected_at'
];

public function listing():BelongsTo{
return $this->belongsTo(Listing::class, 'listing_id');
}

public function bidder():BelongsTo{
return $this->belongsTo(User::class, 'bidder_id');
}
use HasFactory;
}
4 changes: 4 additions & 0 deletions app/Models/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,4 61,8 @@ public function listing():HasMany{
return $this->hasMany(Listing::class, 'by_user_id');
}

public function offers():HasMany{
return $this->hasMany(Offer::class, 'bidder_id');
}

}
44 changes: 44 additions & 0 deletions database/migrations/2024_05_09_093328_create_offers_table.php
Original file line number Diff line number Diff line change
@@ -0,0 1,44 @@
<?php

use App\Models\Listing;
use App\Models\User;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('offers', function (Blueprint $table) {
$table->id();
$table->timestamps();
$table->timestamp('accepted_at')->nullable();
$table->timestamp('rejected_at')->nullable();

$table->foreignIdFor(
Listing::class,
'listing_id'
)->constrained('listings');


$table->foreignIdFor(
User::class,
'bidder_id'
)->constrained('users');

$table->unsignedInteger('amount');
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('offers');
}
};
58 changes: 58 additions & 0 deletions resources/js/Pages/Listing/Show/Components/makeOffer.vue
Original file line number Diff line number Diff line change
@@ -0,0 1,58 @@
<template>
<Box>
<template #header>Make an Offer</template>
<div>
<form @submit.prevent="makeOffer">
<input v-model.number="form.amount" type="text" class="input" />
<input
v-model.number="form.amount"
type="range" :min="min"
:max="max" step="10000"
class="mt-2 w-full h-4 bg-gray-200 rounded-lg appearance-none cursor-pointer dark:bg-gray-700"
/>

<button type="submit" class="btn-outline w-full mt-2 text-sm">
Make an Offer
</button>
</form>
</div>
<div class="flex justify-between text-gray-500 mt-2">
<div>Difference</div>
<div>
<Price :price="difference" />
</div>
</div>
</Box>
</template>

<script setup>
import Price from '@/Components/price.vue'
import Box from '@/Components/UI/box.vue'
import { useForm } from "@inertiajs/vue3";
import { computed, watch } from 'vue'
const props = defineProps({
listingId: Number,
price: Number,
})
const form = useForm({
amount: props.price
})
const makeOffer = () => form.post(
route('listing.offer.store',
{ listing: props.listingId },
),
{
preserveScroll: true,
preserveState: true,
},
)
const difference = computed(() => form.amount - props.price)
const min = computed(() => Math.round(props.price / 2))
const max = computed(() => Math.round(props.price * 2))
const emit = defineEmits(['offerUpdated']);
watch(() => form.amount, () => emit('offerUpdated'))
</script>
20 changes: 13 additions & 7 deletions resources/js/Pages/Listing/show.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 16,6 @@
<ListingSpace :listing="listing" class="text-lg" />
<ListingAddress :listing="listing" class="text-gray" />
</Box>
<Box>
<template #header>Offer</template>
Make an offer
</Box>
<Box>
<template #header>Monthly payment</template>
<label class="label">Interest rate ({{interestRate}}%)</label>
Expand Down Expand Up @@ -51,9 47,13 @@
</div>
</div>
</div>
<MakeOffer

:listing-id="listing.id"
:price="listing.price"
/>
</Box>
</div>

</div>
</template>

Expand All @@ -62,16 62,22 @@ import Box from "@/Components/UI/box.vue";
import ListingAddress from "@/Components/listingAddress.vue";
import ListingSpace from "@/Components/listingSpace.vue";
import Price from "@/Components/price.vue";
import {ref} from 'vue'
import MakeOffer from '@/Pages/Listing/Show/Components/makeOffer.vue'
import {ref, computed} from 'vue'
import {useMonthlyPayment} from '@/Composables/useMonthlyPayment'
import { usePage } from "@inertiajs/vue3";
const interestRate = ref(2.5)
const duration = ref(25)
const props = defineProps({
listing: Object,
});
const page = usePage()
const user = computed(
() => page.props.value.user,
)
const { monthlyPayment, totalPaid, totalInterest } = useMonthlyPayment(
props.listing.price, interestRate, duration,
)</script>
5 changes: 5 additions & 0 deletions routes/web.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 3,7 @@
use App\Http\Controllers\AuthController;
use App\Http\Controllers\IndexController;
use App\Http\Controllers\ListingController;
use App\Http\Controllers\ListingOfferController;
use App\Http\Controllers\RealtorListingController;
use App\Http\Controllers\RealtorListingImageController;
use App\Http\Controllers\UserAccountController;
Expand All @@ -21,6 22,10 @@

Route::resource('user-account', UserAccountController::class)->only(['create', 'store']);

Route::resource('listing.offer', ListingOfferController::class)
->middleware('auth')
->only(['store']);

Route::prefix('realtor')->name('realtor.')->middleware('auth')->group(function(){
Route::name('listing.restore')->put(
'listing/{listing}/restore',
Expand Down

0 comments on commit fbb5ed1

Please sign in to comment.