Add Franchise and Newsletter management features
- Implemented FranchiseController with CRUD operations and data handling. - Created NewsletterController for managing newsletter subscriptions. - Added routes for Franchise and Newsletter resources in web.php. - Developed views for Franchise and Newsletter management including index, create, edit, and datatable actions. - Introduced form handling and validation for Franchise and Newsletter submissions. - Created database migrations for franchises and newsletters tables. - Updated sidebar configuration to include Franchise and Newsletter sections. - Enhanced client-side forms with AJAX submission for Franchise and Newsletter.
This commit is contained in:
116
Modules/CCMS/app/Http/Controllers/FranchiseController.php
Normal file
116
Modules/CCMS/app/Http/Controllers/FranchiseController.php
Normal file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\CCMS\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Rules\Recaptcha;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Modules\CCMS\Models\Franchise;
|
||||
use Yajra\DataTables\Facades\DataTables;
|
||||
|
||||
class FranchiseController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
|
||||
public function index()
|
||||
{
|
||||
if (request()->ajax()) {
|
||||
$model = Franchise::query()->latest();
|
||||
return DataTables::eloquent($model)
|
||||
->addIndexColumn()
|
||||
->addColumn('action', 'ccms::franchise.datatable.action')
|
||||
->rawColumns(['action'])
|
||||
->toJson();
|
||||
}
|
||||
return view('ccms::franchise.index', [
|
||||
'title' => 'Franchise List',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$rules = [
|
||||
'first_name' => 'required|string',
|
||||
'email' => 'required|email',
|
||||
];
|
||||
|
||||
if (setting('enable_reCaptcha') == 1) {
|
||||
$rules['g-recaptcha-response'] = ['required', new Recaptcha];
|
||||
}
|
||||
|
||||
$messages = [
|
||||
'email.email' => 'Must be a valid email address.',
|
||||
'g-recaptcha-response.required' => 'Please complete reCAPTCHA validation.',
|
||||
'g-recaptcha-response' => 'Invalid reCAPTCHA.',
|
||||
];
|
||||
|
||||
$validator = Validator::make($request->all(), $rules, $messages);
|
||||
if ($validator->fails()) {
|
||||
return response()->json(['errors' => $validator->errors()], 422);
|
||||
}
|
||||
|
||||
Franchise::create($validator->validated());
|
||||
|
||||
return response()->json(['status' => 200, 'message' => "Thank you for reaching out! Your message has been received and we'll get back to you shortly."], 200);
|
||||
} catch (\Exception $e) {
|
||||
return response()->json(['status' => 500, 'message' => 'Internal server error', 'error' => $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the specified resource.
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
try {
|
||||
$franchise = Franchise::whereId($id)->first();
|
||||
if ($franchise) {
|
||||
$franchise->delete();
|
||||
}
|
||||
return response()->json(['status' => 200, 'message' => 'Franchise has been deleted!'], 200);
|
||||
} catch (\Throwable $th) {
|
||||
return redirect()->back()->with('error', $th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
115
Modules/CCMS/app/Http/Controllers/NewsletterController.php
Normal file
115
Modules/CCMS/app/Http/Controllers/NewsletterController.php
Normal file
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\CCMS\Http\Controllers;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Rules\Recaptcha;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Http\Response;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
use Modules\CCMS\Models\Newsletter;
|
||||
use Yajra\DataTables\Facades\DataTables;
|
||||
|
||||
class NewsletterController extends Controller
|
||||
{
|
||||
/**
|
||||
* Display a listing of the resource.
|
||||
*/
|
||||
|
||||
public function index()
|
||||
{
|
||||
if (request()->ajax()) {
|
||||
$model = Newsletter::query()->latest();
|
||||
return DataTables::eloquent($model)
|
||||
->addIndexColumn()
|
||||
->addColumn('action', 'ccms::newsletter.datatable.action')
|
||||
->rawColumns(['action'])
|
||||
->toJson();
|
||||
}
|
||||
return view('ccms::newsletter.index', [
|
||||
'title' => 'Newsletter List',
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for creating a new resource.
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a newly created resource in storage.
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$rules = [
|
||||
'email' => 'required|email',
|
||||
];
|
||||
|
||||
if (setting('enable_reCaptcha') == 1) {
|
||||
$rules['g-recaptcha-response'] = ['required', new Recaptcha];
|
||||
}
|
||||
|
||||
$messages = [
|
||||
'email.email' => 'Must be a valid email address.',
|
||||
'g-recaptcha-response.required' => 'Please complete reCAPTCHA validation.',
|
||||
'g-recaptcha-response' => 'Invalid reCAPTCHA.',
|
||||
];
|
||||
|
||||
$validator = Validator::make($request->all(), $rules, $messages);
|
||||
if ($validator->fails()) {
|
||||
return response()->json(['errors' => $validator->errors()], 422);
|
||||
}
|
||||
|
||||
Newsletter::create($validator->validated());
|
||||
|
||||
return response()->json(['status' => 200, 'message' => "Thank you for reaching out! Your message has been received and we'll get back to you shortly."], 200);
|
||||
} catch (\Exception $e) {
|
||||
return response()->json(['status' => 500, 'message' => 'Internal server error', 'error' => $e->getMessage()], 500);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the specified resource.
|
||||
*/
|
||||
public function show($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the form for editing the specified resource.
|
||||
*/
|
||||
public function edit($id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the specified resource in storage.
|
||||
*/
|
||||
public function update(Request $request, $id)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified resource from storage.
|
||||
*/
|
||||
public function destroy($id)
|
||||
{
|
||||
try {
|
||||
$newsletter = Newsletter::whereId($id)->first();
|
||||
if ($newsletter) {
|
||||
$newsletter->delete();
|
||||
}
|
||||
return response()->json(['status' => 200, 'message' => 'Newsletter has been deleted!'], 200);
|
||||
} catch (\Throwable $th) {
|
||||
return redirect()->back()->with('error', $th->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
37
Modules/CCMS/app/Models/Franchise.php
Normal file
37
Modules/CCMS/app/Models/Franchise.php
Normal file
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\CCMS\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
// use Modules\CCMS\Database\Factories\FranchiseFactory;
|
||||
|
||||
class Franchise extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
protected $fillable = [
|
||||
'first_name',
|
||||
'last_name',
|
||||
'email',
|
||||
'phone',
|
||||
'address',
|
||||
'city',
|
||||
'state',
|
||||
'invest_level',
|
||||
'own_business',
|
||||
'yes_own_des',
|
||||
'franchise_location',
|
||||
'start_time_frame',
|
||||
'office_setup',
|
||||
'website'
|
||||
];
|
||||
|
||||
// protected static function newFactory(): FranchiseFactory
|
||||
// {
|
||||
// // return FranchiseFactory::new();
|
||||
// }
|
||||
}
|
19
Modules/CCMS/app/Models/Newsletter.php
Normal file
19
Modules/CCMS/app/Models/Newsletter.php
Normal file
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace Modules\CCMS\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
// use Modules\CCMS\Database\Factories\NewsletterFactory;
|
||||
|
||||
class Newsletter extends Model
|
||||
{
|
||||
use HasFactory;
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
protected $fillable = ['email'];
|
||||
|
||||
|
||||
}
|
@@ -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('newsletters', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('email')->unique();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('newsletters');
|
||||
}
|
||||
};
|
@@ -0,0 +1,40 @@
|
||||
<?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('franchises', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->string('first_name')->nullable();
|
||||
$table->string('last_name')->nullable();
|
||||
$table->string('email')->nullable();
|
||||
$table->string('phone')->nullable();
|
||||
$table->string('address')->nullable();
|
||||
$table->string('city')->nullable();
|
||||
$table->string('state')->nullable();
|
||||
$table->string('invest_level')->nullable();
|
||||
$table->string('own_business')->nullable();
|
||||
$table->text('yes_own_des')->nullable();
|
||||
$table->string('franchise_location')->nullable();
|
||||
$table->string('start_time_frame')->nullable();
|
||||
$table->string('office_setup')->nullable();
|
||||
$table->string('website')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('franchises');
|
||||
}
|
||||
};
|
14
Modules/CCMS/resources/views/franchise/create.blade.php
Normal file
14
Modules/CCMS/resources/views/franchise/create.blade.php
Normal file
@@ -0,0 +1,14 @@
|
||||
@extends('layouts.app')
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
{{ html()->form('POST')->route('testimonial.store')->class(['needs-validation'])->attributes(['enctype' => 'multipart/form-data', 'novalidate'])->open() }}
|
||||
|
||||
@include('ccms::testimonial.partials._form')
|
||||
|
||||
{{ html()->form()->close() }}
|
||||
|
||||
</div>
|
||||
@endsection
|
@@ -0,0 +1,10 @@
|
||||
<div class="hstack flex-wrap gap-3">
|
||||
|
||||
{{-- <a data-link="{{ route('franchise.markAsRead', $id) }}" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Mark as {{ $is_read == 1 ? 'unread' : 'read' }}" data-status="{{ $is_read == 1 ? 'read' : 'unread' }}" --}}
|
||||
{{-- class="fs-15 mark-item"><i class="{{ $is_read == 1 ? ' ri-mail-close-line link-secondary' : ' ri-mail-check-line link-success' }}"></i></a> --}}
|
||||
|
||||
<a href="javascript:void(0);" data-link="{{ route('franchise.destroy', $id) }}" class="link-danger fs-15 remove-item" data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Delete">
|
||||
<i class="ri-delete-bin-6-line"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
14
Modules/CCMS/resources/views/franchise/edit.blade.php
Normal file
14
Modules/CCMS/resources/views/franchise/edit.blade.php
Normal file
@@ -0,0 +1,14 @@
|
||||
@extends('layouts.app')
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
{{ html()->modelForm($testimonial, 'PUT')->route('testimonial.update', $testimonial->id)->class(['needs-validation'])->attributes(['novalidate'])->open() }}
|
||||
|
||||
@include('ccms::testimonial.partials._form')
|
||||
|
||||
{{ html()->form()->close() }}
|
||||
|
||||
</div>
|
||||
@endsection
|
41
Modules/CCMS/resources/views/franchise/index.blade.php
Normal file
41
Modules/CCMS/resources/views/franchise/index.blade.php
Normal file
@@ -0,0 +1,41 @@
|
||||
@extends('layouts.app')
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
<div class="card">
|
||||
<div class="card-header align-items-center d-flex">
|
||||
<h5 class="card-title flex-grow-1 mb-0">{{ $title }}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@php
|
||||
$columns = [
|
||||
[
|
||||
'title' => 'S.N',
|
||||
'data' => 'DT_RowIndex',
|
||||
'name' => 'DT_RowIndex',
|
||||
'orderable' => false,
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
],
|
||||
['title' => 'First Name', 'data' => 'name', 'first_name' => 'first_name'],
|
||||
['title' => 'Last Name', 'data' => 'name', 'first_name' => 'first_name'],
|
||||
['title' => 'Email', 'data' => 'email', 'name' => 'email'],
|
||||
['title' => 'Phone', 'data' => 'phone', 'name' => 'phone'],
|
||||
['title' => 'Address', 'data' => 'address', 'name' => 'address'],
|
||||
['title' => 'City', 'data' => 'city', 'name' => 'city'],
|
||||
['title' => 'State', 'data' => 'state', 'name' => 'state'],
|
||||
['title' => 'Invest Level', 'data' => 'invest_level', 'name' => 'invest_level'],
|
||||
['title' => 'Franchise Location', 'data' => 'franchise_location', 'name' => 'franchise_location'],
|
||||
[
|
||||
'title' => 'Action',
|
||||
'data' => 'action',
|
||||
'orderable' => false,
|
||||
'searchable' => false,
|
||||
],
|
||||
];
|
||||
@endphp
|
||||
<x-data-table-script :route="route('franchise.index')" :reorder="null" :columns="$columns" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
@@ -0,0 +1,71 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-8 col-xl-9">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="row gy-3">
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Name')->class('form-label') }}
|
||||
{{ html()->span('*')->class('text-danger') }}
|
||||
{{ html()->text('title')->class('form-control')->placeholder('Enter Name')->required() }}
|
||||
{{ html()->div('Name is required')->class('invalid-feedback') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Designation')->class('form-label') }}
|
||||
{{ html()->text('designation')->class('form-control')->placeholder('Enter Designation') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Company')->class('form-label') }}
|
||||
{{ html()->text('company')->class('form-control')->placeholder('Enter Company') }}
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6">
|
||||
{{ html()->label('Branch')->class('form-label')->for('branch_id') }}
|
||||
{{ html()->select('branch_id', $branchOptions)->class('form-select choices-select')->placeholder('Select') }}
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
{{ html()->label('Comment')->class('form-label')->for('description') }}
|
||||
{{ html()->span('*')->class('text-danger') }}
|
||||
{{ html()->textarea('description')->class('form-control')->rows(10) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end col -->
|
||||
<div class="col-lg-4 col-xl-3">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Publish</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{ html()->select('status', config('constants.page_status_options'))->class('form-select choices-select ') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end card body -->
|
||||
|
||||
<x-form-buttons :editable="$editable" label="Save" href="{{ route('team.index') }}" />
|
||||
</div>
|
||||
|
||||
<div class="card featured-image-section">
|
||||
<div class="card-header">
|
||||
<h6 class="card-title mb-0 fs-14">
|
||||
Featured
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
{{ html()->label('Image')->class('form-label')->for('image') }}
|
||||
<x-image-input :editable="$editable" id="image" name="image" :data="$editable ? $testimonial->getRawOriginal('image') : null"
|
||||
:multiple="false" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end col -->
|
||||
</div>
|
14
Modules/CCMS/resources/views/newsletter/create.blade.php
Normal file
14
Modules/CCMS/resources/views/newsletter/create.blade.php
Normal file
@@ -0,0 +1,14 @@
|
||||
@extends('layouts.app')
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
{{ html()->form('POST')->route('testimonial.store')->class(['needs-validation'])->attributes(['enctype' => 'multipart/form-data', 'novalidate'])->open() }}
|
||||
|
||||
@include('ccms::testimonial.partials._form')
|
||||
|
||||
{{ html()->form()->close() }}
|
||||
|
||||
</div>
|
||||
@endsection
|
@@ -0,0 +1,8 @@
|
||||
<div class="hstack flex-wrap gap-3">
|
||||
|
||||
<a href="javascript:void(0);" data-link="{{ route('newsletter.destroy', $id) }}" class="link-danger fs-15 remove-item"
|
||||
data-bs-toggle="tooltip" data-bs-placement="bottom" data-bs-title="Delete">
|
||||
<i class="ri-delete-bin-6-line"></i>
|
||||
</a>
|
||||
|
||||
</div>
|
14
Modules/CCMS/resources/views/newsletter/edit.blade.php
Normal file
14
Modules/CCMS/resources/views/newsletter/edit.blade.php
Normal file
@@ -0,0 +1,14 @@
|
||||
@extends('layouts.app')
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
|
||||
{{ html()->modelForm($testimonial, 'PUT')->route('testimonial.update', $testimonial->id)->class(['needs-validation'])->attributes(['novalidate'])->open() }}
|
||||
|
||||
@include('ccms::testimonial.partials._form')
|
||||
|
||||
{{ html()->form()->close() }}
|
||||
|
||||
</div>
|
||||
@endsection
|
33
Modules/CCMS/resources/views/newsletter/index.blade.php
Normal file
33
Modules/CCMS/resources/views/newsletter/index.blade.php
Normal file
@@ -0,0 +1,33 @@
|
||||
@extends('layouts.app')
|
||||
@section('content')
|
||||
<div class="container-fluid">
|
||||
<x-dashboard.breadcumb :title="$title" />
|
||||
<div class="card">
|
||||
<div class="card-header align-items-center d-flex">
|
||||
<h5 class="card-title flex-grow-1 mb-0">{{ $title }}</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
@php
|
||||
$columns = [
|
||||
[
|
||||
'title' => 'S.N',
|
||||
'data' => 'DT_RowIndex',
|
||||
'name' => 'DT_RowIndex',
|
||||
'orderable' => false,
|
||||
'searchable' => false,
|
||||
'sortable' => false,
|
||||
],
|
||||
['title' => 'Email', 'data' => 'email', 'name' => 'email'],
|
||||
[
|
||||
'title' => 'Action',
|
||||
'data' => 'action',
|
||||
'orderable' => false,
|
||||
'searchable' => false,
|
||||
],
|
||||
];
|
||||
@endphp
|
||||
<x-data-table-script :route="route('newsletter.index')" :reorder="null" :columns="$columns" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
@@ -0,0 +1,71 @@
|
||||
<div class="row">
|
||||
<div class="col-lg-8 col-xl-9">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="row gy-3">
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Name')->class('form-label') }}
|
||||
{{ html()->span('*')->class('text-danger') }}
|
||||
{{ html()->text('title')->class('form-control')->placeholder('Enter Name')->required() }}
|
||||
{{ html()->div('Name is required')->class('invalid-feedback') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Designation')->class('form-label') }}
|
||||
{{ html()->text('designation')->class('form-control')->placeholder('Enter Designation') }}
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
{{ html()->label('Company')->class('form-label') }}
|
||||
{{ html()->text('company')->class('form-control')->placeholder('Enter Company') }}
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6">
|
||||
{{ html()->label('Branch')->class('form-label')->for('branch_id') }}
|
||||
{{ html()->select('branch_id', $branchOptions)->class('form-select choices-select')->placeholder('Select') }}
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
{{ html()->label('Comment')->class('form-label')->for('description') }}
|
||||
{{ html()->span('*')->class('text-danger') }}
|
||||
{{ html()->textarea('description')->class('form-control')->rows(10) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end col -->
|
||||
<div class="col-lg-4 col-xl-3">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h5 class="card-title mb-0">Publish</h5>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
{{ html()->select('status', config('constants.page_status_options'))->class('form-select choices-select ') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end card body -->
|
||||
|
||||
<x-form-buttons :editable="$editable" label="Save" href="{{ route('team.index') }}" />
|
||||
</div>
|
||||
|
||||
<div class="card featured-image-section">
|
||||
<div class="card-header">
|
||||
<h6 class="card-title mb-0 fs-14">
|
||||
Featured
|
||||
</h6>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
{{ html()->label('Image')->class('form-label')->for('image') }}
|
||||
<x-image-input :editable="$editable" id="image" name="image" :data="$editable ? $testimonial->getRawOriginal('image') : null"
|
||||
:multiple="false" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- end col -->
|
||||
</div>
|
@@ -10,9 +10,11 @@ use Modules\CCMS\Http\Controllers\CountryController;
|
||||
use Modules\CCMS\Http\Controllers\EnquiryController;
|
||||
use Modules\CCMS\Http\Controllers\FaqCategoryController;
|
||||
use Modules\CCMS\Http\Controllers\FaqController;
|
||||
use Modules\CCMS\Http\Controllers\FranchiseController;
|
||||
use Modules\CCMS\Http\Controllers\GalleryCategoryController;
|
||||
use Modules\CCMS\Http\Controllers\GalleryController;
|
||||
use Modules\CCMS\Http\Controllers\InstitutionController;
|
||||
use Modules\CCMS\Http\Controllers\NewsletterController;
|
||||
use Modules\CCMS\Http\Controllers\PageController;
|
||||
use Modules\CCMS\Http\Controllers\PartnerController;
|
||||
use Modules\CCMS\Http\Controllers\PopupController;
|
||||
@@ -124,5 +126,8 @@ Route::group(['middleware' => ['web', 'auth', 'permission'], 'prefix' => 'admin/
|
||||
Route::get('enquiry/mark-as-read/{id}', [EnquiryController::class, 'markAsRead'])->name('enquiry.markAsRead');
|
||||
Route::resource('enquiry', EnquiryController::class)->names('enquiry')->only(['index', 'store', 'destroy']);
|
||||
|
||||
Route::resource('franchise', FranchiseController::class)->names('franchise')->only(['index', 'store', 'destroy']);
|
||||
Route::resource('newsletter', NewsletterController::class)->names('newsletter')->only(['index', 'store', 'destroy']);
|
||||
|
||||
Route::resource('counselor', CounselorController::class)->names('counselor')->only(['index', 'store', 'destroy']);
|
||||
});
|
||||
|
@@ -45,6 +45,38 @@ return [
|
||||
'can' => ['menu.index'],
|
||||
],
|
||||
|
||||
[
|
||||
'text' => 'Enquiries',
|
||||
'icon' => 'ri-cellphone-line',
|
||||
'module' => 'CCMS',
|
||||
'submenu' => [
|
||||
|
||||
[
|
||||
'text' => 'Enquiry',
|
||||
'url' => 'admin/enquiry',
|
||||
'can' => ['enquiry.index'],
|
||||
],
|
||||
|
||||
[
|
||||
'text' => 'Counsellor Request',
|
||||
'url' => 'admin/counselor',
|
||||
'can' => ['counselor.index'],
|
||||
],
|
||||
|
||||
[
|
||||
'text' => 'Franchise Request',
|
||||
'url' => 'admin/franchise',
|
||||
// 'can' => ['franchise.index'],
|
||||
],
|
||||
|
||||
[
|
||||
'text' => 'Newsletter',
|
||||
'url' => 'admin/newsletter',
|
||||
// 'can' => ['newsletter.index'],
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
[
|
||||
'text' => 'Offer Popup',
|
||||
'url' => 'admin/popup',
|
||||
@@ -181,21 +213,7 @@ return [
|
||||
],
|
||||
],
|
||||
|
||||
[
|
||||
'text' => 'Enquiry',
|
||||
'url' => 'admin/enquiry',
|
||||
'icon' => ' ri-cellphone-line',
|
||||
'module' => 'CCMS',
|
||||
'can' => ['enquiry.index'],
|
||||
],
|
||||
|
||||
[
|
||||
'text' => 'Counsellor Request',
|
||||
'url' => 'admin/counselor',
|
||||
'icon' => ' ri-cellphone-line',
|
||||
'module' => 'CCMS',
|
||||
'can' => ['counselor.index'],
|
||||
],
|
||||
|
||||
[
|
||||
'text' => 'Course Finder',
|
||||
|
@@ -219,6 +219,86 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const form = document.getElementById('franchise-form');
|
||||
const submitBtn = document.getElementById('franchise-submit');
|
||||
const url = form.action;
|
||||
form.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
submitBtn.disabled = true;
|
||||
submitBtn.textContent = 'Submitting…';
|
||||
const formData = new FormData(form);
|
||||
try {
|
||||
const res = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')
|
||||
.content
|
||||
},
|
||||
body: formData
|
||||
});
|
||||
const data = await res.json();
|
||||
if (res.ok) {
|
||||
form.reset();
|
||||
window.location.href =
|
||||
"{{ route('thankyou') }}"; // ✅ redirect instead of toastr
|
||||
} else if (data.errors && data.errors.email) {
|
||||
data.errors.email.forEach(msg => toastr.error(msg));
|
||||
} else {
|
||||
toastr.error('Submission failed. Please try again.');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
toastr.error('Something went wrong. Please try again.');
|
||||
} finally {
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.textContent = 'Submit';
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const form = document.getElementById('newsletter-form');
|
||||
const submitBtn = document.getElementById('newsletter-submit');
|
||||
const url = form.action;
|
||||
form.addEventListener('submit', async (e) => {
|
||||
e.preventDefault();
|
||||
submitBtn.disabled = true;
|
||||
submitBtn.textContent = 'Submitting…';
|
||||
const formData = new FormData(form);
|
||||
try {
|
||||
const res = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]')
|
||||
.content
|
||||
},
|
||||
body: formData
|
||||
});
|
||||
const data = await res.json();
|
||||
if (res.ok) {
|
||||
form.reset();
|
||||
window.location.href =
|
||||
"{{ route('thankyou') }}"; // ✅ redirect instead of toastr
|
||||
} else if (data.errors && data.errors.email) {
|
||||
data.errors.email.forEach(msg => toastr.error(msg));
|
||||
} else {
|
||||
toastr.error('Submission failed. Please try again.');
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
toastr.error('Something went wrong. Please try again.');
|
||||
} finally {
|
||||
submitBtn.disabled = false;
|
||||
submitBtn.textContent = 'Submit';
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const form = document.getElementById('counselor-form');
|
||||
|
@@ -61,10 +61,12 @@
|
||||
<a href="{{ setting('whatsapp') }}" target="blank"> <i
|
||||
class="fa-brands fa-square-whatsapp"></i></a>
|
||||
</div>
|
||||
<form class="flex" action="">
|
||||
<form action="{{ route('newsletter.store') }}" method="post" id="newsletter-form">
|
||||
@csrf
|
||||
<input class=" border-0 w-80percent px-20 text-14 py-10 text-black" type="email"
|
||||
name="email" id="email" placeholder="Enter your Email">
|
||||
<button class="border-0 text-white p-10 text-12 ">Subscribe</button>
|
||||
<button type="submit" id="newsletter-submit"
|
||||
class="border-0 text-white p-10 text-12 newsletter-submit">Subscribe</button>
|
||||
</form>
|
||||
<div>
|
||||
<iframe
|
||||
|
@@ -33,12 +33,10 @@
|
||||
<div class="quote-mark">"</div>
|
||||
|
||||
|
||||
<h2 class="heading">Your Trusted Study Abroad Partner.</h2>
|
||||
<h2 class="heading">{{$page->short_description}}</h2>
|
||||
|
||||
<p class="message">
|
||||
We’re more than just a consultancy—we’re your ultimate study abroad ally! With years of
|
||||
experience and a passion for helping students succeed, we’ve guided thousands of students to
|
||||
their dream universities across the globe. Your dreams are our mission
|
||||
{!! $page->description !!}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -101,19 +101,20 @@
|
||||
|
||||
<div class="franchise-form bg-white">
|
||||
|
||||
<form action="">
|
||||
<form action="{{ route('franchise.store') }}" method="post" id="franchise-form">
|
||||
@csrf
|
||||
<label class="text-16 pb-5" for="">Your Name <span
|
||||
class="text-brand">(Required)</span></label>
|
||||
<div class="flex gap-10 ">
|
||||
<div class="w-full">
|
||||
<label class="text-14 pb-5" for="">First</label>
|
||||
<input class="w-full mb-30 rounded-6 py-10 text-14 px-10" type="text" name=""
|
||||
id="">
|
||||
<input class="w-full mb-30 rounded-6 py-10 text-14 px-10" type="text"
|
||||
name="first_name" id="">
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<label class="text-14 pb-5" for="">Last</label>
|
||||
<input class="w-full mb-30 rounded-6 py-10 text-14 px-10" type="text" name=""
|
||||
id="">
|
||||
<input class="w-full mb-30 rounded-6 py-10 text-14 px-10" type="text"
|
||||
name="last_name" id="">
|
||||
</div>
|
||||
|
||||
|
||||
@@ -123,33 +124,33 @@
|
||||
|
||||
<label class="text-16 pb-5" for="">Your Email Address <span
|
||||
class="text-brand">(Required)</span></label>
|
||||
<input class="w-full mb-20 rounded-6 py-10 text-14 px-10" type="email" name=""
|
||||
<input class="w-full mb-20 rounded-6 py-10 text-14 px-10" type="email" name="email"
|
||||
id="">
|
||||
|
||||
|
||||
|
||||
<label class="text-16 pb-5" for="">Your Phone <span
|
||||
class="text-brand">(Required)</span></label>
|
||||
<input class="w-full mb-20 rounded-6 py-10 text-14 px-10" type="text" name=""
|
||||
<input class="w-full mb-20 rounded-6 py-10 text-14 px-10" type="text" name="phone"
|
||||
id="">
|
||||
|
||||
|
||||
<label class="text-16 pb-5" for="">Your Address <span
|
||||
class="text-brand">(Required)</span></label>
|
||||
|
||||
<input class="w-full mb-20 rounded-6 py-10 text-14 px-10" type="text" name=""
|
||||
<input class="w-full mb-20 rounded-6 py-10 text-14 px-10" type="text" name="address"
|
||||
id="">
|
||||
|
||||
<div class="flex gap-10 ">
|
||||
<div class="w-full">
|
||||
<label class="text-14 pb-5" for="">City</label>
|
||||
<input class="w-full mb-30 rounded-6 py-10 text-14 px-10" type="text"
|
||||
name="" id="">
|
||||
name="city" id="">
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<label class="text-14 pb-5" for="">State/Region/Province</label>
|
||||
<input class="w-full mb-30 rounded-6 py-10 text-14 px-10" type="text"
|
||||
name="" id="">
|
||||
name="state" id="">
|
||||
</div>
|
||||
|
||||
|
||||
@@ -161,7 +162,7 @@
|
||||
<div class="sm:block flex gap-10 ">
|
||||
<div class="w-full">
|
||||
<label class="text-14 pb-5" for="">Level to Invest</label>
|
||||
<select class="w-full py-5" name="" id="">
|
||||
<select class="w-full py-5" name="invest_level" id="">
|
||||
<option value="">Less than $20,000</option>
|
||||
<option value="">Less than $30,000</option>
|
||||
<option value="">Less than $40,000</option>
|
||||
@@ -169,9 +170,9 @@
|
||||
</select>
|
||||
|
||||
<!-- <select name="" id="franchise-invest">
|
||||
<option value="" selected hidden> Less than $10,000</option>
|
||||
<option value=""></option>
|
||||
</select> -->
|
||||
<option value="" selected hidden> Less than $10,000</option>
|
||||
<option value=""></option>
|
||||
</select> -->
|
||||
|
||||
|
||||
</div>
|
||||
@@ -179,7 +180,7 @@
|
||||
<label class="text-14 pb-5" for="">Do you currently own a business?
|
||||
(Yes/No)</label>
|
||||
<input class="w-full mb-30 rounded-6 py-10 text-14 px-10" type="text"
|
||||
name="" id="">
|
||||
name="own_business" id="">
|
||||
</div>
|
||||
|
||||
|
||||
@@ -192,26 +193,26 @@
|
||||
business</label>
|
||||
|
||||
|
||||
<textarea class="w-full mb-20 rounded-6 py-10 text-14 px-10" name="" id=""></textarea>
|
||||
<textarea class="w-full mb-20 rounded-6 py-10 text-14 px-10" name="yes_own_des" id=""></textarea>
|
||||
|
||||
|
||||
<div class="sm:block flex gap-10 ">
|
||||
<div class="w-full">
|
||||
<label class="text-14 pb-5" for="">Preferred Franchise Location</label>
|
||||
<input class="w-full mb-30 rounded-6 py-10 text-14 px-10" type="text"
|
||||
name="" id="">
|
||||
name="franchise_location" id="">
|
||||
</div>
|
||||
<div class="w-full">
|
||||
<label class="text-14 pb-5" for="">Timeframe to Start</label>
|
||||
<select class="w-full py-5" name="" id="">
|
||||
<select class="w-full py-5" name="start_time_frame" id="">
|
||||
<option value="">within 1 year</option>
|
||||
<option value="">After 1 year</option>
|
||||
|
||||
</select>
|
||||
<!-- <select name="" id="franchise-timeframe">
|
||||
<option value="" selected hidden> within 6 months</option>
|
||||
<option value=""></option>
|
||||
</select> -->
|
||||
<option value="" selected hidden> within 6 months</option>
|
||||
<option value=""></option>
|
||||
</select> -->
|
||||
</div>
|
||||
|
||||
|
||||
@@ -221,17 +222,18 @@
|
||||
</div>
|
||||
<div class="sm:w-full w-50percent">
|
||||
<label class="text-14 pb-5" for="">Do u already have an office setup ?</label>
|
||||
<input class="w-full mb-30 rounded-6 py-10 text-14 px-10" type="text" name=""
|
||||
id="">
|
||||
<input class="w-full mb-30 rounded-6 py-10 text-14 px-10" type="text"
|
||||
name="office_setup" id="">
|
||||
</div>
|
||||
|
||||
<label class="text-14 pb-5" for=""> Please add your bussiness portfolio website ,and
|
||||
let us know
|
||||
if you have any questions?</label>
|
||||
<textarea class="w-full mb-20 rounded-6 py-10 text-14 px-10" name="" id=""></textarea>
|
||||
<textarea class="w-full mb-20 rounded-6 py-10 text-14 px-10" name="website" id=""></textarea>
|
||||
|
||||
|
||||
<button class="button-hover px-20 py-10 bg-sec text-white text-16 border-0">Send
|
||||
<button type="submit" id="franchise-submit"
|
||||
class="button-hover px-20 py-10 bg-sec text-white text-16 border-0 franchise-submit">Send
|
||||
Message</button>
|
||||
</form>
|
||||
</div>
|
||||
|
@@ -7,22 +7,24 @@
|
||||
</div>
|
||||
|
||||
<section class="container py-30 free-resources">
|
||||
<div class="row">
|
||||
<div class="col col-md-3"></div>
|
||||
<div class="col col-md-9">
|
||||
<div class="flex justify-between items-center ">
|
||||
<div>
|
||||
<div class="row">
|
||||
<div class="col col-md-3"></div>
|
||||
<div class="col col-md-9">
|
||||
<div class="flex justify-between items-center ">
|
||||
<div>
|
||||
|
||||
|
||||
<h2 class="md:text-30 text-60 text-sec"> {{ $page->title }}</h2>
|
||||
<div class="title-line "></div>
|
||||
<h2 class="md:text-30 text-60 text-sec"> {{ $page->title }}</h2>
|
||||
<div class="title-line "></div>
|
||||
</div>
|
||||
<button class="review-button"><p>Review</p></button>
|
||||
<button class="review-button">
|
||||
<p>Review</p>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@if ($page->children)
|
||||
@@ -82,49 +84,61 @@
|
||||
|
||||
|
||||
|
||||
@php
|
||||
$accordionId = "accordion-questions-{$index}";
|
||||
@endphp
|
||||
|
||||
<div class="py-40">
|
||||
<h3 class="text-20 text-brand">
|
||||
{{ $page->title }} FAQ's
|
||||
Frequently Asked Questions
|
||||
</h3>
|
||||
<div class="accordion accordion-title-underlined accordion-sm pt-20"
|
||||
id="accordion-questions" role="tablist" aria-multiselectable="true">
|
||||
@foreach ($page->custom as $key => $value)
|
||||
|
||||
<div class="accordion accordion-title-underlined accordion-sm pt-20"
|
||||
id="{{ $accordionId }}" role="tablist" aria-multiselectable="true">
|
||||
|
||||
@foreach ($child->custom as $key => $item)
|
||||
@php
|
||||
$headingId = "heading-{$index}-{$key}";
|
||||
$collapseId = "collapse-{$index}-{$key}";
|
||||
@endphp
|
||||
|
||||
<div class="accordion-item panel mb-10">
|
||||
<div class="accordion-heading" role="tab"
|
||||
id="heading-question-{{ $key + 1 }}">
|
||||
id="{{ $headingId }}">
|
||||
<h4 class="accordion-title">
|
||||
<a class="collapsed text-17 font-bold" role="button"
|
||||
data-bs-toggle="collapse"
|
||||
data-bs-parent="#accordion-questions"
|
||||
href="index.php#collapse-question-item-{{ $key + 1 }}"
|
||||
aria-expanded="false"
|
||||
aria-controls="collapse-question-item-{{ $key + 1 }}">
|
||||
<span
|
||||
class="accordion-expander text-16 text-black"><i
|
||||
href="#{{ $collapseId }}"
|
||||
aria-expanded="{{ $loop->first ? 'true' : 'false' }}"
|
||||
aria-controls="{{ $collapseId }}">
|
||||
<span class="accordion-expander text-16 text-black">
|
||||
<i
|
||||
class="lqd-icn-ess icon-ion-ios-arrow-forward"></i>
|
||||
<i
|
||||
class="lqd-icn-ess icon-ion-ios-arrow-forward"></i></span><span
|
||||
class="accordion-title-txt">{{ $value['icon'] ?? '' }}</span>
|
||||
class="lqd-icn-ess icon-ion-ios-arrow-forward"></i>
|
||||
</span>
|
||||
<span
|
||||
class="accordion-title-txt">{{ $item['icon'] ?? '' }}</span>
|
||||
</a>
|
||||
</h4>
|
||||
</div>
|
||||
<div id="collapse-question-item-{{ $key + 1 }}"
|
||||
class="accordion-collapse collapse"
|
||||
data-bs-parent="#accordion-questions" role="tabpanel"
|
||||
aria-labelledby="heading-question-{{ $key + 1 }}">
|
||||
|
||||
<div id="{{ $collapseId }}"
|
||||
class="accordion-collapse collapse {{ $loop->first ? 'show' : '' }}"
|
||||
data-bs-parent="#{{ $accordionId }}" role="tabpanel"
|
||||
aria-labelledby="{{ $headingId }}">
|
||||
<div
|
||||
class="accordion-content text-14 leading-20 text-black">
|
||||
<p>{{ $value['key'] ?? '' }}</p>
|
||||
<p>{{ $item['key'] ?? '' }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endforeach
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- blog -->
|
||||
<div class="lqd-section blog pt-20" id="blog" data-custom-animations="true"
|
||||
{{-- <div class="lqd-section blog pt-20" id="blog" data-custom-animations="true"
|
||||
data-ca-options='{"animationTarget": ".btn, .animation-element", "ease": "power4.out", "initValues":{"x": "-10px", "y": "10px", "opacity":0} , "animations":{"x": "0px", "y": "0px", "opacity":1}}'>
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
@@ -174,7 +188,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> --}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
Reference in New Issue
Block a user