Skip to content

Commit

Permalink
fix: #94 require billing name and email on team creation
Browse files Browse the repository at this point in the history
  • Loading branch information
bohdan-shulha committed Aug 4, 2024
1 parent d2d1263 commit a57f2b1
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 40 deletions.
4 changes: 4 additions & 0 deletions app/Actions/Jetstream/CreateTeam.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,17 @@ public function create(User $user, array $input): Team

Validator::make($input, [
'name' => ['required', 'string', 'max:255'],
'billing_name' => ['required', 'string', 'max:255'],
'billing_email' => ['required', 'string', 'max:255', 'unique:teams'],
])->validateWithBag('createTeam');

AddingTeam::dispatch($user);

$user->switchTeam($team = $user->ownedTeams()->create([
'name' => $input['name'],
'personal_team' => false,
'billing_name' => $input['billing_name'],
'billing_email' => $input['billing_email'],
]));

return $team;
Expand Down
6 changes: 2 additions & 4 deletions app/Http/Controllers/TeamBillingController.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
namespace App\Http\Controllers;

use App\Models\Team;
use Carbon\Carbon;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;
Expand All @@ -16,9 +15,8 @@ public function show(Team $team)
{
$customer = $team->createAsCustomer();

// dd($team->subscription()->nextPayment());
$checkout = $team->subscribe('pri_01j2ag2ts45hznad1t67bs4syd')->returnTo(route('teams.billing.show', $team));
//$team->subscription()->anchorBillingCycleOn(Carbon::now()->addMonth()->startOfMonth());

$nextPayment = $team->subscription()?->nextPayment();

//Cashier::api()
Expand All @@ -43,7 +41,7 @@ public function updateCustomer(Team $team, Request $request)
{
$formData = $request->validate([
'name' => 'required',
'email' => 'required|email',
'email' => ['required', 'email', 'unique:teams,billing_email'],
]);

DB::transaction(function () use ($team, $formData) {
Expand Down
19 changes: 19 additions & 0 deletions app/Models/Team.php
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,17 @@ protected function casts(): array
];
}

protected static function booted(): void
{
self::deleting(function (Team $team) {
$team->nodes()->delete();

if ($team->subscription()?->active() && ! $team->subscription()->ends_at) {
$team->subscription()->cancelNow();
}
});
}

protected function nodes(): HasMany
{
return $this->hasMany(Node::class);
Expand All @@ -67,6 +78,10 @@ protected function nodes(): HasMany
*/
protected function paddleName(): string
{
if ($this->billing_name) {
return $this->billing_name;
}

return $this->owner->name;
}

Expand All @@ -75,6 +90,10 @@ protected function paddleName(): string
*/
protected function paddleEmail(): string
{
if ($this->billing_email) {
return $this->billing_email;
}

return $this->owner->email;
}

Expand Down
39 changes: 21 additions & 18 deletions resources/js/Components/FormField.vue
Original file line number Diff line number Diff line change
@@ -1,36 +1,39 @@
<script setup>
import {ref, onMounted, reactive, onActivated} from 'vue';
import { ref, onMounted, reactive, onActivated } from "vue";
import InputLabel from "@/Components/InputLabel.vue";
import InputError from "@/Components/InputError.vue";
const props = defineProps({
'error': String,
})
error: String,
});
const slot = ref(null);
const state = reactive({
domId: ''
domId: "",
});
onMounted(() => {
state.domId = 'f-' + Math.random().toString(36).slice(2);
slot.value.children[0]?.setAttribute('id', state.domId);
})
state.domId = "f-" + Math.random().toString(36).slice(2);
slot.value.children[0]?.setAttribute("id", state.domId);
});
</script>
<template>
<div v-auto-animate>
<InputLabel :for="state.domId">
<slot name="label" />
</InputLabel>
<div v-auto-animate>
<InputLabel :for="state.domId">
<slot name="label" />
</InputLabel>
<div ref="slot">
<slot />
</div>
<div ref="slot">
<slot />
</div>
<div v-if="$slots.hint" class="text-sm text-gray-500 pt-2">
<slot name="hint" />
</div>
<InputError :message="$props.error" class="mt-2" />
</div>
</template>
<InputError :message="$props.error" class="mt-2" />
</div>
</template>
12 changes: 10 additions & 2 deletions resources/js/Pages/Teams/Billing.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import TextInput from "@/Components/TextInput.vue";
import { useForm } from "@inertiajs/vue3";
import ExternalLink from "@/Components/ExternalLink.vue";
import SecondaryButton from "@/Components/SecondaryButton.vue";
import SectionBorder from "@/Components/SectionBorder.vue";
const props = defineProps({
team: Object,
Expand Down Expand Up @@ -50,13 +51,16 @@ const updatePaymentMethod = () => {
</template>

<template #form>
<FormField class="col-span-4">
<FormField class="col-span-4" :error="customerForm.errors.name">
<template #label> Business Name </template>

<TextInput v-model="customerForm.name" class="w-full" />
</FormField>

<FormField class="col-span-4">
<FormField
class="col-span-4"
:error="customerForm.errors.email"
>
<template #label> Business Email </template>

<TextInput v-model="customerForm.email" class="w-full" />
Expand All @@ -73,6 +77,8 @@ const updatePaymentMethod = () => {
</template>
</FormSection>

<SectionBorder />

<ActionSection>
<template #title> Next Payment </template>

Expand Down Expand Up @@ -166,6 +172,8 @@ const updatePaymentMethod = () => {
</template>
</ActionSection>

<SectionBorder />

<ActionSection>
<template #title> Transactions </template>

Expand Down
71 changes: 55 additions & 16 deletions resources/js/Pages/Teams/Partials/CreateTeamForm.vue
Original file line number Diff line number Diff line change
@@ -1,28 +1,58 @@
<script setup>
import { useForm } from '@inertiajs/vue3';
import FormSection from '@/Components/FormSection.vue';
import InputError from '@/Components/InputError.vue';
import InputLabel from '@/Components/InputLabel.vue';
import PrimaryButton from '@/Components/PrimaryButton.vue';
import TextInput from '@/Components/TextInput.vue';
import { useForm } from "@inertiajs/vue3";
import FormSection from "@/Components/FormSection.vue";
import InputError from "@/Components/InputError.vue";
import InputLabel from "@/Components/InputLabel.vue";
import PrimaryButton from "@/Components/PrimaryButton.vue";
import TextInput from "@/Components/TextInput.vue";
import FormField from "@/Components/FormField.vue";
import ActionSection from "@/Components/ActionSection.vue";
const form = useForm({
name: '',
name: "",
billing_name: "",
billing_email: "",
});
const createTeam = () => {
form.post(route('teams.store'), {
errorBag: 'createTeam',
form.post(route("teams.store"), {
errorBag: "createTeam",
preserveScroll: true,
});
};
</script>

<template>
<FormSection @submitted="createTeam">
<template #title>
Team Details
<ActionSection>
<template #title> Customer Details </template>

<template #description>
Invoices and receipts will be sent to the specified E-Mail address.
</template>

<template #content>
<FormField class="col-span-4" :error="form.errors.billing_name">
<template #label> Business Name </template>

<TextInput v-model="form.billing_name" class="w-full" />
</FormField>

<FormField class="col-span-4" :error="form.errors.billing_email">
<template #label> Business Email </template>

<TextInput v-model="form.billing_email" class="w-full" />

<template #hint>
E-Mails should be unique. You can use '+' sign to use the
same email for multiple teams. For example,
[email protected]
</template>
</FormField>
</template>
</ActionSection>

<FormSection @submitted="createTeam">
<template #title> Team Details </template>

<template #description>
Create a new team to collaborate with others on projects.
Expand All @@ -33,10 +63,16 @@ const createTeam = () => {
<InputLabel value="Team Owner" />

<div class="flex items-center mt-2">
<img class="object-cover w-12 h-12 rounded-full" :src="$page.props.auth.user.profile_photo_url" :alt="$page.props.auth.user.name">
<img
class="object-cover w-12 h-12 rounded-full"
:src="$page.props.auth.user.profile_photo_url"
:alt="$page.props.auth.user.name"
/>

<div class="ms-4 leading-tight">
<div class="text-gray-900 dark:text-white">{{ $page.props.auth.user.name }}</div>
<div class="text-gray-900 dark:text-white">
{{ $page.props.auth.user.name }}
</div>
<div class="text-sm text-gray-700 dark:text-gray-300">
{{ $page.props.auth.user.email }}
</div>
Expand All @@ -57,8 +93,11 @@ const createTeam = () => {
</div>
</template>

<template #actions>
<PrimaryButton :class="{ 'opacity-25': form.processing }" :disabled="form.processing">
<template #submit>
<PrimaryButton
:class="{ 'opacity-25': form.processing }"
:disabled="form.processing"
>
Create
</PrimaryButton>
</template>
Expand Down

0 comments on commit a57f2b1

Please sign in to comment.