feat: FAQ controller made
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled

This commit is contained in:
2025-10-27 15:18:31 +05:45
parent db9315ad22
commit 48e089d3c8
13 changed files with 274 additions and 3 deletions

View File

@@ -0,0 +1,45 @@
<?php
namespace App\Http\Controllers\Client;
use App\Http\Controllers\Controller;
use App\Models\FAQ;
use Illuminate\Http\Request;
use Inertia\Inertia;
class FaqController extends Controller
{
public function index()
{
$faqs = FAQ::all();
$faqResponse = $faqs->map(function ($item) {
return [
'question' => $item->question,
'answer' => $item->answer,
];
});
return Inertia::render("dashboard/faq/index", ['faq' => $faqResponse]);
}
public function add()
{
return Inertia::render("dashboard/faq/add");
}
public function addFaq(Request $request)
{
$validated = $request->validate([
"question" => "required|string",
"answer" => "required|string"
]);
$faq = FAQ::create($validated);
$faqResponse = [
"question" => $faq->question,
"answer" => $faq->answer,
];
return to_route("dashboard.faq.show", ['faq' => $faqResponse]);
}
}

View File

@@ -80,7 +80,15 @@ class HomeController extends Controller
public function faq()
{
return Inertia::render('faq');
$faq = FAQ::all();
$faqResponse = $faq->map(function ($item) {
return [
"id" => $item->id,
"question" => $item->question,
"answer" => $item->answer,
];
});
return Inertia::render('faq', ['faq' => $faqResponse]);
}
}

14
app/Models/FAQ.php Normal file
View File

@@ -0,0 +1,14 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class FAQ extends Model
{
protected $table = "faqs";
protected $fillable = [
"question",
"answer"
];
}

View File

@@ -0,0 +1,28 @@
<?php
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('faqs', function (Blueprint $table) {
$table->id();
$table->string("question");
$table->string('answer');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('faqs');
}
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 KiB

View File

@@ -0,0 +1,91 @@
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import AppLayout from '@/layouts/app-layout';
import dashboard from '@/routes/dashboard';
import { Head, useForm } from '@inertiajs/react';
import FilePondPluginImageExifOrientation from 'filepond-plugin-image-exif-orientation';
import FilePondPluginImagePreview from 'filepond-plugin-image-preview';
import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css';
import 'filepond/dist/filepond.min.css';
import { registerPlugin } from 'react-filepond';
import { toast } from 'sonner';
registerPlugin(FilePondPluginImageExifOrientation, FilePondPluginImagePreview);
export default function FaqAdd() {
const { data, setData, post, processing, errors, wasSuccessful } = useForm({
question: '',
answer: '',
});
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
post(dashboard.faq.addFaq().url, {
forceFormData: true,
});
if (wasSuccessful) {
toast.success('Product added successfully');
}
};
return (
<AppLayout>
<Head title="Add FAQ Questions" />
<section className="flex flex-col gap-8 px-8 py-8">
<h1 className="text-lg font-semibold tracking-tight">
Add FAQ Questions
</h1>
<form
onSubmit={handleSubmit}
method="POST"
encType="multipart/formdata"
className="flex flex-col items-start gap-4"
>
<div className="flex w-full flex-col gap-2">
<Label htmlFor="question">Question</Label>
<Input
type="text"
id="question"
value={data.question}
onChange={(e) =>
setData('question', e.target.value)
}
className="rounded border p-2"
/>
{errors.question && (
<span className="text-red-600">
{errors.question}
</span>
)}
</div>
<div className="flex w-full flex-col gap-2">
<Label htmlFor="answer">Answer</Label>
<Input
type="text"
id="answer"
value={data.answer}
onChange={(e) => setData('answer', e.target.value)}
className="rounded border p-2"
/>
{errors.answer && (
<span className="text-red-600">
{errors.answer}
</span>
)}
</div>
<Button
type="submit"
disabled={processing}
className="cursor-pointer"
>
{processing ? 'submitting...' : 'Submit'}
</Button>
</form>
</section>
</AppLayout>
);
}

View File

@@ -0,0 +1,76 @@
import { Button } from '@/components/ui/button';
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table';
import AppLayout from '@/layouts/app-layout';
import dashboard from '@/routes/dashboard';
import { Head, Link } from '@inertiajs/react';
import { Pencil, Trash2 } from 'lucide-react';
export default function Faq({
faq,
}: {
faq: [{ question: string; answer: string }];
}) {
return (
<AppLayout
breadcrumbs={[
{ title: 'FAQs', href: dashboard.product.index().url },
]}
>
<Head title="FAQs" />
<section className="flex flex-col gap-8 px-8 py-8">
<div className="flex items-center justify-between">
<h1 className="text-xl font-semibold tracking-tight">
FAQs
</h1>
<Link href={dashboard.faq.add()}>
<Button className="cursor-pointer">
Add Questions
</Button>
</Link>
</div>
<Table>
<TableHeader>
<TableRow>
<TableHead className="w-[80px]">S.N.</TableHead>
<TableHead>Question</TableHead>
<TableHead>Answer</TableHead>
<TableHead className="text-right">Action</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{faq.map((item, index) => (
<TableRow key={index}>
<TableCell className="font-medium">
{index + 1}
</TableCell>
<TableCell>{item.question}</TableCell>
<TableCell>{item.answer}</TableCell>
<TableCell className="text-right">
<div className="flex items-center justify-end gap-2">
<Link href="">
<Pencil size={18} />
</Link>
<Link href="">
<Trash2
size={18}
color={'#D2042D'}
/>
</Link>
</div>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</section>
</AppLayout>
);
}

View File

@@ -13,7 +13,11 @@ import img3 from '@asset/img/Bespoke/Shrek.jpg';
import img2 from '@asset/img/Bespoke/Swarovsky embedded wall hang.jpg';
import { Head, Link } from '@inertiajs/react';
export default function Faq() {
export default function Faq({
faq,
}: {
faq: [{ id: number; question: string; answer: string }];
}) {
return (
<>
<Layout>
@@ -67,7 +71,7 @@ export default function Faq() {
type="single"
collapsible
className="w-full"
defaultValue="item-1"
defaultValue="1"
>
{faq.map((item) => (
<AccordionItem value={`${item.id}`}>

View File

@@ -2,6 +2,7 @@
use App\Http\Controllers\Auth\DashboardController;
use App\Http\Controllers\Client\AboutController;
use App\Http\Controllers\Client\FaqController;
use App\Http\Controllers\Client\HomeController;
use App\Http\Controllers\client\ProductController;
use App\Http\Controllers\Client\TestimonialController;
@@ -38,6 +39,10 @@ Route::post('/testimonial', [TestimonialController::class, 'store'])->name('test
Route::middleware(['auth', 'verified'])->name("dashboard.")->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index'])->name('index');
Route::get('/faq/show', [FaqController::class, 'index'])->name('faq.show');
Route::get('/faq/add', [FaqController::class, 'add'])->name('faq.add');
Route::post('/faq/add', [FaqController::class, 'addFaq'])->name('faq.addFaq');
Route::get('/product/dashboard', [ProductController::class, 'index'])->name('product.index');
Route::get('/product/add', [ProductController::class, 'productAdd'])->name('product.add');