diff --git a/docs/_data/manifest.json b/docs/_data/manifest.json index 24620cc8..07dd4cc5 100644 --- a/docs/_data/manifest.json +++ b/docs/_data/manifest.json @@ -1,5 +1,5 @@ { - "dist/main.css": "/dist/main.123ef729.css", + "dist/main.css": "/dist/main.28df35f9.css", "dist/main.js": "/dist/main.3be5bc06.js", "dist/455.3a7b4474.css": "/dist/455.3a7b4474.css", "dist/455.095e6545.js": "/dist/455.095e6545.js", diff --git a/docs/_layouts/inertia.html b/docs/_layouts/inertia.html new file mode 100644 index 00000000..712ecf64 --- /dev/null +++ b/docs/_layouts/inertia.html @@ -0,0 +1,1912 @@ +--- +layout: default +--- + +
+ PHPFlasher + works seamlessly with Inertia.js, providing a smooth way to display flash notifications in your single-page applications. +
+ + ++ If you need to use PHP < v8.2, Laravel < v11.0, or an older Inertia.js version, use + PHPFlasher v1 instead. + + Check out the v1 documentation here + . +
++ To use PHPFlasher with Inertia.js, + you'll need to install both the PHP package and JavaScript package. +
+ +composer require php-flasher/flasher-laravel
+ Add @flasher/flasher to your package.json:
{
+ "dependencies": {
+ "@flasher/flasher": "file:vendor/php-flasher/flasher/Resources"
+ }
+}
+ Then, install the JavaScript dependencies:
+ +npm install --force
+
+ The --force flag is required because we're installing a local package from the filesystem
+ rather than from npm. This is the recommended approach for PHPFlasher to ensure version compatibility.
+
+ To use PHPFlasher + with Inertia.js, you need to: +
+ +Update your HandleInertiaRequests middleware to share flash notifications:
flash()->render('array'),
+
+ // You can include other shared data here
+ 'auth' => [
+ 'user' => $request->user(),
+ ],
+ 'flash' => [
+ 'success' => fn () => $request->session()->get('success'),
+ 'error' => fn () => $request->session()->get('error'),
+ ],
+ ]);
+ }
+}
+
+ The render('array') method
+ converts flash messages to a format compatible with JavaScript. You can also use render('json') and
+ parse it in your frontend code.
+
Add the code to render notifications in your layout component (example shown with Vue.js):
+ +<script>
+import flasher from "@flasher/flasher";
+
+export default {
+ props: {
+ messages: Object,
+ },
+ watch: {
+ messages(value) {
+ if (value) {
+ flasher.render(value);
+ }
+ }
+ },
+ mounted() {
+ // Display messages on initial load
+ if (this.messages) {
+ flasher.render(this.messages);
+ }
+ }
+}
+</script>
+
+<template>
+ <div>
+ <header class="bg-white shadow">
+ <div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
+ <!-- Your navigation -->
+ <h1 class="text-xl font-bold text-gray-900">My App</h1>
+ </div>
+ </header>
+
+ <main>
+ <div class="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
+ <slot />
+ </div>
+ </main>
+
+ <footer class="bg-white border-t border-gray-200 mt-auto">
+ <div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
+ <p class="text-center text-gray-500 text-sm">
+ © 2025 My Application
+ </p>
+ </div>
+ </footer>
+ </div>
+</template>
+ Now you can create flash notifications in your controllers:
+ + User::all()
+ ]);
+ }
+
+ /**
+ * Show the form for creating a new user.
+ */
+ public function create()
+ {
+ return Inertia::render('Users/Create');
+ }
+
+ /**
+ * Store a newly created user in storage.
+ */
+ public function store(Request $request)
+ {
+ $validated = $request->validate([
+ 'name' => 'required|string|max:255',
+ 'email' => 'required|string|email|max:255|unique:users',
+ 'password' => 'required|string|min:8|confirmed',
+ ]);
+
+ User::create([
+ 'name' => $validated['name'],
+ 'email' => $validated['email'],
+ 'password' => Hash::make($validated['password']),
+ ]);
+
+ // Add a success notification
+ flash()->success('User created successfully!');
+
+ // Redirect back, and Inertia will handle passing the flash message
+ return Redirect::route('users.index');
+ }
+
+ /**
+ * Display the specified user.
+ */
+ public function show(User $user)
+ {
+ return Inertia::render('Users/Show', [
+ 'user' => $user
+ ]);
+ }
+
+ /**
+ * Show the form for editing the specified user.
+ */
+ public function edit(User $user)
+ {
+ return Inertia::render('Users/Edit', [
+ 'user' => $user
+ ]);
+ }
+
+ /**
+ * Update the specified user in storage.
+ */
+ public function update(Request $request, User $user)
+ {
+ $validated = $request->validate([
+ 'name' => 'required|string|max:255',
+ 'email' => 'required|string|email|max:255|unique:users,email,' . $user->id,
+ ]);
+
+ $user->update($validated);
+
+ flash()->success('User updated successfully!');
+
+ return Redirect::route('users.index');
+ }
+
+ /**
+ * Remove the specified user from storage.
+ */
+ public function destroy(User $user)
+ {
+ $user->delete();
+
+ flash()->info('User has been deleted.');
+
+ return Redirect::route('users.index');
+ }
+}
+ flash()->success('Item created successfully!')
+ flash()->error('An error occurred!')
+ flash()->warning('Please review your submission.')
+ flash()->info('Your session expires in 10 minutes.')
+ watch property to detect new notifications after navigation or form submissions.
+ Here's a complete example of CRUD operations with flash messages:
+ + Product::all()
+ ]);
+ }
+
+ /**
+ * Show the form for creating a new product.
+ */
+ public function create()
+ {
+ return Inertia::render('Products/Create');
+ }
+
+ /**
+ * Store a newly created product in storage.
+ */
+ public function store(Request $request)
+ {
+ $validated = $request->validate([
+ 'name' => 'required|string|max:255',
+ 'price' => 'required|numeric',
+ 'description' => 'nullable|string|max:1000',
+ 'category_id' => 'required|exists:categories,id',
+ ]);
+
+ Product::create($validated);
+
+ flash()->success('Product created successfully!');
+
+ return Redirect::route('products.index');
+ }
+
+ /**
+ * Display the specified product.
+ */
+ public function show(Product $product)
+ {
+ return Inertia::render('Products/Show', [
+ 'product' => $product->load('category')
+ ]);
+ }
+
+ /**
+ * Show the form for editing the specified product.
+ */
+ public function edit(Product $product)
+ {
+ return Inertia::render('Products/Edit', [
+ 'product' => $product,
+ 'categories' => \App\Models\Category::all()
+ ]);
+ }
+
+ /**
+ * Update the specified product in storage.
+ */
+ public function update(Request $request, Product $product)
+ {
+ $validated = $request->validate([
+ 'name' => 'required|string|max:255',
+ 'price' => 'required|numeric',
+ 'description' => 'nullable|string|max:1000',
+ 'category_id' => 'required|exists:categories,id',
+ ]);
+
+ $product->update($validated);
+
+ flash()->success('Product updated successfully!');
+
+ return Redirect::route('products.index');
+ }
+
+ /**
+ * Remove the specified product from storage.
+ */
+ public function destroy(Product $product)
+ {
+ try {
+ $product->delete();
+ flash()->info('Product has been deleted.');
+ } catch (\Exception $e) {
+ flash()->error('Cannot delete this product. It may be in use.');
+ }
+
+ return Redirect::route('products.index');
+ }
+}
+ + Always wrap database operations in try-catch blocks and provide user-friendly error messages. + This helps users understand what went wrong and what actions they can take to resolve issues. +
+Here's an example of using flash notifications in an authentication flow:
+ +validate([
+ 'email' => 'required|email',
+ 'password' => 'required',
+ ]);
+
+ if (Auth::attempt($credentials, $request->boolean('remember'))) {
+ $request->session()->regenerate();
+
+ flash()->success('Welcome back, ' . Auth::user()->name . '!');
+
+ return Redirect::intended(route('dashboard'));
+ }
+
+ throw ValidationException::withMessages([
+ 'email' => __('auth.failed'),
+ ]);
+ }
+
+ /**
+ * Show registration form
+ */
+ public function showRegistration()
+ {
+ return Inertia::render('Auth/Register');
+ }
+
+ /**
+ * Handle user registration
+ */
+ public function register(Request $request)
+ {
+ $validated = $request->validate([
+ 'name' => 'required|string|max:255',
+ 'email' => 'required|string|email|max:255|unique:users',
+ 'password' => 'required|string|min:8|confirmed',
+ ]);
+
+ $user = User::create([
+ 'name' => $validated['name'],
+ 'email' => $validated['email'],
+ 'password' => Hash::make($validated['password']),
+ ]);
+
+ Auth::login($user);
+
+ flash()->success('Welcome to our application! Your account has been created.');
+
+ return Redirect::route('dashboard');
+ }
+
+ /**
+ * Log the user out
+ */
+ public function logout(Request $request)
+ {
+ Auth::logout();
+
+ $request->session()->invalidate();
+ $request->session()->regenerateToken();
+
+ flash()->info('You have been logged out successfully.');
+
+ return Redirect::route('login');
+ }
+}
+ Combine PHPFlasher with Inertia's validation error handling:
+ +validate([
+ 'name' => 'required|string|max:255',
+ 'email' => 'required|email',
+ 'message' => 'required|string|min:10|max:1000',
+ ]);
+
+ // Process the form data
+ // e.g., send an email, save to database, etc.
+
+ // Show success notification
+ flash()->success(
+ 'Thank you for contacting us! We will get back to you soon.',
+ 'Message Sent'
+ );
+
+ return Redirect::route('contact.thankyou');
+
+ } catch (\Illuminate\Validation\ValidationException $e) {
+ // With Inertia, validation errors are automatically passed back
+ // Add a generic error message as well
+ flash()->error('Please fix the errors in your form.', 'Form Validation Error');
+
+ // With Inertia, this will redirect back with errors
+ throw $e;
+ } catch (\Exception $e) {
+ // Handle other exceptions
+ flash()->error(
+ 'Sorry, we could not process your request. Please try again later.',
+ 'System Error'
+ );
+
+ return Redirect::back();
+ }
+ }
+
+ /**
+ * Show thank you page
+ */
+ public function showThankYou()
+ {
+ return Inertia::render('Contact/ThankYou');
+ }
+}
+ <script setup>
+import { useForm } from '@inertiajs/vue3'
+import Layout from '@/Layouts/MainLayout.vue'
+
+const form = useForm({
+ name: '',
+ email: '',
+ message: ''
+})
+
+const submit = () => {
+ form.post(route('contact.submit'))
+}
+</script>
+
+<template>
+ <Layout>
+ <div class="max-w-2xl mx-auto p-4 sm:p-6 lg:p-8">
+ <h1 class="text-2xl font-semibold text-gray-900 mb-6">Contact Us</h1>
+
+ <form @submit.prevent="submit" class="space-y-6">
+ <div>
+ <label for="name" class="block text-sm font-medium text-gray-700">Name</label>
+ <input
+ id="name"
+ v-model="form.name"
+ type="text"
+ class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-emerald-500 focus:ring focus:ring-emerald-200 focus:ring-opacity-50"
+ />
+ <div v-if="form.errors.name" class="text-red-500 text-sm mt-1">{{ form.errors.name }}</div>
+ </div>
+
+ <div>
+ <label for="email" class="block text-sm font-medium text-gray-700">Email</label>
+ <input
+ id="email"
+ v-model="form.email"
+ type="email"
+ class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-emerald-500 focus:ring focus:ring-emerald-200 focus:ring-opacity-50"
+ />
+ <div v-if="form.errors.email" class="text-red-500 text-sm mt-1">{{ form.errors.email }}</div>
+ </div>
+
+ <div>
+ <label for="message" class="block text-sm font-medium text-gray-700">Message</label>
+ <textarea
+ id="message"
+ v-model="form.message"
+ rows="4"
+ class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-emerald-500 focus:ring focus:ring-emerald-200 focus:ring-opacity-50"
+ ></textarea>
+ <div v-if="form.errors.message" class="text-red-500 text-sm mt-1">{{ form.errors.message }}</div>
+ </div>
+
+ <div class="flex justify-end">
+ <button
+ type="submit"
+ :disabled="form.processing"
+ class="inline-flex items-center px-4 py-2 bg-emerald-600 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-emerald-700 active:bg-emerald-800 focus:outline-none focus:border-emerald-800 focus:ring focus:ring-emerald-300 disabled:opacity-25 transition"
+ >
+ <span v-if="form.processing">Processing...</span>
+ <span v-else>Submit</span>
+ </button>
+ </div>
+ </form>
+ </div>
+ </Layout>
+</template>
+ + As shown in the example above, it's often helpful to use PHPFlasher for global form status messages + while using Inertia's built-in error handling for field-specific validation errors. + This gives users both context-specific and general feedback. +
++ Inertia.js works with multiple frontend frameworks. Here's how to integrate PHPFlasher with each: +
+ + +<script setup>
+import { computed, watch } from 'vue'
+import { usePage } from '@inertiajs/vue3'
+import flasher from '@flasher/flasher'
+
+// Access shared data from Inertia
+const page = usePage()
+const messages = computed(() => page.props.messages)
+
+// Watch for changes in flash messages
+watch(
+ messages,
+ (newMessages) => {
+ if (newMessages) {
+ flasher.render(newMessages)
+ }
+ },
+ { immediate: true }
+)
+</script>
+
+<template>
+ <div class="min-h-screen bg-gray-100">
+ <nav class="bg-white border-b border-gray-100">
+ <!-- Navigation content -->
+ </nav>
+
+ <!-- Page Content -->
+ <main>
+ <slot />
+ </main>
+
+ <footer class="bg-white border-t border-gray-100 mt-auto">
+ <!-- Footer content -->
+ </footer>
+ </div>
+</template>
+ Using flash messages in a Vue component:
+ +<script setup>
+import { useForm } from '@inertiajs/vue3'
+import AppLayout from '@/Layouts/AppLayout.vue'
+import flasher from '@flasher/flasher'
+
+const form = useForm({
+ title: '',
+ content: ''
+})
+
+const submit = () => {
+ form.post(route('posts.store'), {
+ onSuccess: () => {
+ // You can also trigger notifications directly from the frontend
+ flasher.success('Post created from the frontend!')
+
+ // Reset the form
+ form.reset()
+ }
+ })
+}
+</script>
+
+<template>
+ <AppLayout>
+ <div class="py-12">
+ <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
+ <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
+ <div class="p-6 bg-white border-b border-gray-200">
+ <form @submit.prevent="submit">
+ <!-- Form fields -->
+ <button type="submit" :disabled="form.processing">Create Post</button>
+ </form>
+ </div>
+ </div>
+ </div>
+ </div>
+ </AppLayout>
+</template>
+ Use the watch function with immediate: true to ensure flash messages are shown on both initial load and after navigation.
With React, use useEffect with messages as a dependency to catch updates to flash messages.
Combine onMount and afterUpdate lifecycle functions to ensure flash messages are shown both initially and after updates.
Customize your notifications with various options:
+ +option('position', 'bottom-right')
+ ->success('Positioned at the bottom-right');
+
+ return back();
+ }
+
+ public function timeoutExample()
+ {
+ // Timeout
+ flash()
+ ->option('timeout', 8000) // 8 seconds
+ ->info('This message stays longer');
+
+ return back();
+ }
+
+ public function animationExample()
+ {
+ // Animation
+ flash()
+ ->option('showAnimation', 'fadeIn')
+ ->option('hideAnimation', 'fadeOut')
+ ->success('Custom animations');
+
+ return back();
+ }
+
+ public function multipleOptionsExample()
+ {
+ // Multiple options at once
+ flash()
+ ->options([
+ 'position' => 'top-center',
+ 'timeout' => 3000,
+ 'closeButton' => false
+ ])
+ ->success('Multiple options at once');
+
+ return back();
+ }
+}
+ Use SweetAlert for interactive confirmations in your Inertia application:
+ + $post
+ ]);
+ }
+
+ /**
+ * Delete the post
+ */
+ public function destroy(Post $post)
+ {
+ $post->delete();
+
+ flash()->success('Post deleted successfully');
+
+ return Redirect::route('posts.index');
+ }
+}
+ <script setup>
+import { onMounted } from 'vue'
+import { router } from '@inertiajs/vue3'
+import AppLayout from '@/Layouts/AppLayout.vue'
+import flasher from '@flasher/flasher'
+
+const props = defineProps({
+ post: Object
+})
+
+onMounted(() => {
+ flasher.addListener('sweetalert:confirmed', () => {
+ // When confirmed, delete the post
+ router.delete(route('posts.destroy', props.post.id))
+ })
+
+ flasher.addListener('sweetalert:cancelled', () => {
+ // When cancelled, navigate back to the posts list
+ router.get(route('posts.index'))
+ })
+
+ // Show the SweetAlert confirmation dialog
+ flasher.option('title', 'Are you sure?')
+ .option('text', `You are about to delete "${props.post.title}"`)
+ .option('icon', 'warning')
+ .option('showCancelButton', true)
+ .option('confirmButtonText', 'Yes, delete it!')
+ .option('cancelButtonText', 'No, cancel')
+ .option('confirmButtonColor', '#10b981')
+ .option('cancelButtonColor', '#ef4444')
+ .flash('sweetalert')
+})
+</script>
+
+<template>
+ <AppLayout>
+ <div class="py-12">
+ <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
+ <div class="bg-white overflow-hidden shadow-sm sm:rounded-lg">
+ <div class="p-6 bg-white border-b border-gray-200">
+ <p>Processing your request...</p>
+ </div>
+ </div>
+ </div>
+ </div>
+ </AppLayout>
+</template>
+ Set global default options for all notifications:
+ + 'flasher',
+
+ // Global default options
+ 'options' => [
+ 'timeout' => 5000,
+ 'position' => 'top-right',
+ 'showProgressBar' => true,
+ 'closeButton' => true,
+ 'theme' => 'light',
+ ],
+
+ // Presets for common notifications
+ 'presets' => [
+ 'created' => [
+ 'type' => 'success',
+ 'message' => 'The :resource was created successfully.',
+ ],
+ 'updated' => [
+ 'type' => 'success',
+ 'message' => 'The :resource was updated successfully.',
+ ],
+ 'deleted' => [
+ 'type' => 'info',
+ 'message' => 'The :resource was deleted.',
+ ],
+ 'error' => [
+ 'type' => 'error',
+ 'message' => 'An error occurred while processing your request.',
+ ],
+ ],
+];
+ + Use the global configuration file to maintain consistent styling and behavior across your application. + This ensures a unified user experience and makes it easier to update styles app-wide in the future. +
+Choose from 6+ themes including Toastr, SweetAlert, Notyf, Noty and more.
+ + View themes + +Support for multiple languages and right-to-left (RTL) layouts.
+ + Learn more + +Access the full JavaScript API for creating notifications directly from the frontend.
+ + Learn more + +Start using PHPFlasher today and + give your users beautiful notifications in minutes!
+