Merge pull request #25 from truncgil/feature/online-payment
Fix payment form validation, styling and blog header visibility
This commit is contained in:
@@ -21,7 +21,7 @@ class BlogCategoryResource extends Resource
|
||||
{
|
||||
protected static ?string $model = BlogCategory::class;
|
||||
|
||||
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedTag;
|
||||
protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-tag';
|
||||
|
||||
protected static UnitEnum|string|null $navigationGroup = 'Blog';
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ class BlogResource extends Resource
|
||||
{
|
||||
protected static ?string $model = Blog::class;
|
||||
|
||||
protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedDocumentText;
|
||||
protected static string|BackedEnum|null $navigationIcon = 'heroicon-o-document-text';
|
||||
|
||||
public static function getNavigationLabel(): string
|
||||
{
|
||||
|
||||
@@ -74,6 +74,7 @@ class PageSettingsSection
|
||||
'corporate.logos' => 'Logolarımız (Kurumsal)',
|
||||
'corporate.partners' => 'Çözüm Ortaklarımız (Kurumsal)',
|
||||
'corporate.bank-accounts' => 'Banka Bilgilerimiz (Kurumsal)',
|
||||
'corporate.online-payment' => 'Online Ödeme (Kurumsal)',
|
||||
])
|
||||
->default('default')
|
||||
->columnSpanFull(),
|
||||
|
||||
@@ -57,12 +57,14 @@ class BlogController extends Controller
|
||||
$headerTemplate = HeaderTemplate::find($blogPage->header_template_id);
|
||||
}
|
||||
|
||||
// 2. Öncelik: Varsayılan aktif template
|
||||
// 2. Öncelik: Varsayılan aktif template (KALDIRILDI - Default static header kullanılmalı)
|
||||
/*
|
||||
if (!$headerTemplate) {
|
||||
$headerTemplate = HeaderTemplate::where('is_active', true)
|
||||
->latest('updated_at')
|
||||
->first();
|
||||
}
|
||||
*/
|
||||
|
||||
if ($headerTemplate) {
|
||||
$templateDefaults = $headerTemplate->default_data ?? [];
|
||||
@@ -164,17 +166,26 @@ class BlogController extends Controller
|
||||
->orderBy('created_at', 'desc')
|
||||
->get();
|
||||
|
||||
// Render Header Template - En son aktif olan header template'i kullan
|
||||
// Blog sayfa ayarlarını bul (varsa)
|
||||
$blogPage = Page::where('slug', 'blog')->first();
|
||||
|
||||
// Render Header Template
|
||||
$renderedHeader = null;
|
||||
$headerTemplate = HeaderTemplate::where('is_active', true)
|
||||
->latest('updated_at')
|
||||
->first();
|
||||
$headerTemplate = null;
|
||||
|
||||
// 1. Öncelik: Blog sayfasında seçili header template
|
||||
if ($blogPage && $blogPage->header_template_id) {
|
||||
$headerTemplate = HeaderTemplate::find($blogPage->header_template_id);
|
||||
}
|
||||
|
||||
if ($headerTemplate) {
|
||||
$templateDefaults = $headerTemplate->default_data ?? [];
|
||||
$pageData = $blogPage ? ($blogPage->header_data ?? []) : [];
|
||||
$mergedData = array_merge($templateDefaults, $pageData);
|
||||
|
||||
$renderedHeader = TemplateService::replacePlaceholders(
|
||||
$headerTemplate->html_content,
|
||||
$templateDefaults,
|
||||
$mergedData,
|
||||
$post
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,170 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers;
|
||||
|
||||
use App\Models\Page;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Validator;
|
||||
|
||||
class PaymentController extends Controller
|
||||
{
|
||||
public function process(Request $request)
|
||||
{
|
||||
$validator = Validator::make($request->all(), [
|
||||
'name' => 'required|string|max:255',
|
||||
'surname' => 'required|string|max:255',
|
||||
'email' => 'required|email|max:255',
|
||||
'phone' => 'required|string|max:20',
|
||||
'price' => 'required|numeric|min:1',
|
||||
'address' => 'required|string',
|
||||
'agreement' => 'accepted',
|
||||
], [
|
||||
'name.required' => 'Lütfen adınızı giriniz.',
|
||||
'surname.required' => 'Lütfen soyadınızı giriniz.',
|
||||
'email.required' => 'Lütfen e-posta adresinizi giriniz.',
|
||||
'email.email' => 'Geçerli bir e-posta adresi giriniz.',
|
||||
'phone.required' => 'Lütfen telefon numaranızı giriniz.',
|
||||
'price.required' => 'Lütfen ödeme tutarını giriniz.',
|
||||
'price.min' => 'Ödeme tutarı en az 1 TL olmalıdır.',
|
||||
'address.required' => 'Lütfen ödeme açıklamasını giriniz.',
|
||||
'agreement.accepted' => 'Lütfen sözleşmeyi onaylayınız.',
|
||||
]);
|
||||
|
||||
if ($validator->fails()) {
|
||||
Log::info('Payment Validation Failed', $validator->errors()->toArray());
|
||||
|
||||
return back()->withErrors($validator)->withInput();
|
||||
}
|
||||
|
||||
$merchant_id = '127117';
|
||||
$merchant_key = 's9GH5FMuxFtqjxyJ';
|
||||
$merchant_salt = 'qTHTx3j4FjieXPP3';
|
||||
|
||||
$price = $request->input('price') * 100; // Krş cinsinden
|
||||
|
||||
// Get user IP (handling Cloudflare or standard)
|
||||
if (isset($_SERVER['HTTP_CLIENT_IP'])) {
|
||||
$ip = $_SERVER['HTTP_CLIENT_IP'];
|
||||
} elseif (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
|
||||
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
|
||||
} else {
|
||||
$ip = $_SERVER['REMOTE_ADDR'];
|
||||
}
|
||||
$user_ip = $ip;
|
||||
|
||||
$merchant_oid = time(); // Benzersiz sipariş no
|
||||
$email = $request->input('email');
|
||||
$payment_amount = $price;
|
||||
$currency = 'TL'; // Default
|
||||
$test_mode = 0; // Canlı mod
|
||||
|
||||
$user_name = $request->input('name').' '.$request->input('surname');
|
||||
$user_address = $request->input('address'); // Note field used as address
|
||||
$user_phone = $request->input('phone');
|
||||
|
||||
// Callbacks should ideally be routes we define, but user provided specific URLs.
|
||||
// We will use routes relative to current domain or the ones user specified if they are absolute?
|
||||
// The user script had: "https://www.truncgil.com.tr/pay.php?ok"
|
||||
// I should probably use the current app's URL.
|
||||
$merchant_ok_url = route('payment.success');
|
||||
$merchant_fail_url = route('payment.fail');
|
||||
|
||||
$user_basket = base64_encode(json_encode([
|
||||
['Web / Mobil Yazılım', $payment_amount, 1],
|
||||
]));
|
||||
|
||||
$no_installment = 0;
|
||||
$max_installment = 9;
|
||||
$debug_on = 1;
|
||||
$timeout_limit = 30;
|
||||
|
||||
$hash_str = $merchant_id.$user_ip.$merchant_oid.$email.$payment_amount.$user_basket.$no_installment.$max_installment.$currency.$test_mode;
|
||||
$paytr_token = base64_encode(hash_hmac('sha256', $hash_str.$merchant_salt, $merchant_key, true));
|
||||
|
||||
$post_vals = [
|
||||
'merchant_id' => $merchant_id,
|
||||
'user_ip' => $user_ip,
|
||||
'merchant_oid' => $merchant_oid,
|
||||
'email' => $email,
|
||||
'lang' => 'tr',
|
||||
'payment_amount' => $payment_amount,
|
||||
'paytr_token' => $paytr_token,
|
||||
'user_basket' => $user_basket,
|
||||
'debug_on' => $debug_on,
|
||||
'no_installment' => $no_installment,
|
||||
'max_installment' => $max_installment,
|
||||
'user_name' => $user_name,
|
||||
'user_address' => $user_address,
|
||||
'user_phone' => $user_phone,
|
||||
'merchant_ok_url' => $merchant_ok_url,
|
||||
'merchant_fail_url' => $merchant_fail_url,
|
||||
'timeout_limit' => $timeout_limit,
|
||||
'currency' => $currency,
|
||||
'test_mode' => $test_mode,
|
||||
];
|
||||
|
||||
// Curl request
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, 'https://www.paytr.com/odeme/api/get-token');
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_vals);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
|
||||
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
|
||||
curl_setopt($ch, CURLOPT_FRESH_CONNECT, true);
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 20);
|
||||
$result = @curl_exec($ch);
|
||||
|
||||
if (curl_errno($ch)) {
|
||||
return back()->with('error', 'PAYTR connection error. err:'.curl_error($ch));
|
||||
}
|
||||
curl_close($ch);
|
||||
|
||||
$result = json_decode($result, 1);
|
||||
|
||||
if ($result['status'] == 'success') {
|
||||
$token = $result['token'];
|
||||
|
||||
// Re-render the online-payment page but with the token
|
||||
// We need to fetch the page content again
|
||||
// Assuming the slug is 'online-odeme' or similar, or we can just pass a dummy page object
|
||||
// if we are lazy, but correct way is to fetch the page associated with the route.
|
||||
// Since we are POSTing here, we don't know the Page model context unless we fetch it.
|
||||
// Let's try to assume 'online-odeme' which is common.
|
||||
|
||||
$page = Page::where('template', 'online-payment')->orWhere('slug', 'online-odeme')->first();
|
||||
if (! $page) {
|
||||
$page = new Page(['title' => 'Online Ödeme', 'content' => '', 'excerpt' => 'Please complete your payment below.']);
|
||||
}
|
||||
|
||||
return view('templates.corporate.online-payment', [
|
||||
'page' => $page,
|
||||
'paytr_token' => $token,
|
||||
]);
|
||||
|
||||
} else {
|
||||
return back()->with('error', 'PAYTR failed. reason:'.$result['reason']);
|
||||
}
|
||||
}
|
||||
|
||||
public function success(Request $request)
|
||||
{
|
||||
$page = Page::where('template', 'online-payment')->orWhere('slug', 'online-odeme')->first();
|
||||
if ($page) {
|
||||
return redirect()->route('page.show', $page->slug)->with('success', 'Your payment has been charged successfully. This will appear on your credit card statement as "PAYTR ODEME HIZMETLERI"');
|
||||
}
|
||||
|
||||
return redirect()->route('home')->with('success', 'Your payment has been charged successfully.');
|
||||
}
|
||||
|
||||
public function fail(Request $request)
|
||||
{
|
||||
$page = Page::where('template', 'online-payment')->orWhere('slug', 'online-odeme')->first();
|
||||
if ($page) {
|
||||
return redirect()->route('page.show', $page->slug)->with('error', 'Your payment has not been charged successfully! Please check your credit card information.');
|
||||
}
|
||||
|
||||
return redirect()->route('home')->with('error', 'Your payment has not been charged successfully! Please check your credit card information.');
|
||||
}
|
||||
}
|
||||
@@ -11,13 +11,6 @@ use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
class PagePolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
public function before(AuthUser $user, $ability)
|
||||
{
|
||||
if ($user->hasRole('super_admin')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public function viewAny(AuthUser $authUser): bool
|
||||
{
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use Illuminate\Foundation\Auth\User as AuthUser;
|
||||
use App\Models\ProductCategory;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class ProductCategoryPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
public function viewAny(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('ViewAny:ProductCategory');
|
||||
}
|
||||
|
||||
public function view(AuthUser $authUser, ProductCategory $productCategory): bool
|
||||
{
|
||||
return $authUser->can('View:ProductCategory');
|
||||
}
|
||||
|
||||
public function create(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('Create:ProductCategory');
|
||||
}
|
||||
|
||||
public function update(AuthUser $authUser, ProductCategory $productCategory): bool
|
||||
{
|
||||
return $authUser->can('Update:ProductCategory');
|
||||
}
|
||||
|
||||
public function delete(AuthUser $authUser, ProductCategory $productCategory): bool
|
||||
{
|
||||
return $authUser->can('Delete:ProductCategory');
|
||||
}
|
||||
|
||||
public function restore(AuthUser $authUser, ProductCategory $productCategory): bool
|
||||
{
|
||||
return $authUser->can('Restore:ProductCategory');
|
||||
}
|
||||
|
||||
public function forceDelete(AuthUser $authUser, ProductCategory $productCategory): bool
|
||||
{
|
||||
return $authUser->can('ForceDelete:ProductCategory');
|
||||
}
|
||||
|
||||
public function forceDeleteAny(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('ForceDeleteAny:ProductCategory');
|
||||
}
|
||||
|
||||
public function restoreAny(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('RestoreAny:ProductCategory');
|
||||
}
|
||||
|
||||
public function replicate(AuthUser $authUser, ProductCategory $productCategory): bool
|
||||
{
|
||||
return $authUser->can('Replicate:ProductCategory');
|
||||
}
|
||||
|
||||
public function reorder(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('Reorder:ProductCategory');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use Illuminate\Foundation\Auth\User as AuthUser;
|
||||
use App\Models\Product;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class ProductPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
public function viewAny(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('ViewAny:Product');
|
||||
}
|
||||
|
||||
public function view(AuthUser $authUser, Product $product): bool
|
||||
{
|
||||
return $authUser->can('View:Product');
|
||||
}
|
||||
|
||||
public function create(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('Create:Product');
|
||||
}
|
||||
|
||||
public function update(AuthUser $authUser, Product $product): bool
|
||||
{
|
||||
return $authUser->can('Update:Product');
|
||||
}
|
||||
|
||||
public function delete(AuthUser $authUser, Product $product): bool
|
||||
{
|
||||
return $authUser->can('Delete:Product');
|
||||
}
|
||||
|
||||
public function restore(AuthUser $authUser, Product $product): bool
|
||||
{
|
||||
return $authUser->can('Restore:Product');
|
||||
}
|
||||
|
||||
public function forceDelete(AuthUser $authUser, Product $product): bool
|
||||
{
|
||||
return $authUser->can('ForceDelete:Product');
|
||||
}
|
||||
|
||||
public function forceDeleteAny(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('ForceDeleteAny:Product');
|
||||
}
|
||||
|
||||
public function restoreAny(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('RestoreAny:Product');
|
||||
}
|
||||
|
||||
public function replicate(AuthUser $authUser, Product $product): bool
|
||||
{
|
||||
return $authUser->can('Replicate:Product');
|
||||
}
|
||||
|
||||
public function reorder(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('Reorder:Product');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Policies;
|
||||
|
||||
use Illuminate\Foundation\Auth\User as AuthUser;
|
||||
use App\Models\SiteTranslation;
|
||||
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||
|
||||
class SiteTranslationPolicy
|
||||
{
|
||||
use HandlesAuthorization;
|
||||
|
||||
public function viewAny(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('ViewAny:SiteTranslation');
|
||||
}
|
||||
|
||||
public function view(AuthUser $authUser, SiteTranslation $siteTranslation): bool
|
||||
{
|
||||
return $authUser->can('View:SiteTranslation');
|
||||
}
|
||||
|
||||
public function create(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('Create:SiteTranslation');
|
||||
}
|
||||
|
||||
public function update(AuthUser $authUser, SiteTranslation $siteTranslation): bool
|
||||
{
|
||||
return $authUser->can('Update:SiteTranslation');
|
||||
}
|
||||
|
||||
public function delete(AuthUser $authUser, SiteTranslation $siteTranslation): bool
|
||||
{
|
||||
return $authUser->can('Delete:SiteTranslation');
|
||||
}
|
||||
|
||||
public function restore(AuthUser $authUser, SiteTranslation $siteTranslation): bool
|
||||
{
|
||||
return $authUser->can('Restore:SiteTranslation');
|
||||
}
|
||||
|
||||
public function forceDelete(AuthUser $authUser, SiteTranslation $siteTranslation): bool
|
||||
{
|
||||
return $authUser->can('ForceDelete:SiteTranslation');
|
||||
}
|
||||
|
||||
public function forceDeleteAny(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('ForceDeleteAny:SiteTranslation');
|
||||
}
|
||||
|
||||
public function restoreAny(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('RestoreAny:SiteTranslation');
|
||||
}
|
||||
|
||||
public function replicate(AuthUser $authUser, SiteTranslation $siteTranslation): bool
|
||||
{
|
||||
return $authUser->can('Replicate:SiteTranslation');
|
||||
}
|
||||
|
||||
public function reorder(AuthUser $authUser): bool
|
||||
{
|
||||
return $authUser->can('Reorder:SiteTranslation');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?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('visions', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
Schema::dropIfExists('visions');
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,206 @@
|
||||
@extends('layouts.site')
|
||||
|
||||
@section('content')
|
||||
|
||||
<section class="wrapper bg-white py-14 xl:py-20 relative">
|
||||
<div class="container">
|
||||
<div class="row align-items-center mb-12">
|
||||
<div class="col-lg-8 mx-auto text-center">
|
||||
<div class="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-orange-100 text-orange-600 text-sm font-bold mb-4">
|
||||
<i class="uil uil-shield-check text-lg"></i>
|
||||
{!! t('256-Bit SSL Güvenli Ödeme') !!}
|
||||
</div>
|
||||
<h1 class="display-3 font-bold text-slate-800 mb-3">{!! $page->title !!}</h1>
|
||||
<p class="lead text-slate-500 max-w-2xl mx-auto">{!! $page->excerpt ?? t('Kredi kartınızla hızlı, kolay ve güvenli ödeme yapın.') !!}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if(session('success'))
|
||||
<div class="row mb-8">
|
||||
<div class="col-lg-8 mx-auto">
|
||||
<div class="alert alert-success bg-green-100 text-green-700 border-green-200 rounded-xl p-4 flex items-center gap-3">
|
||||
<i class="uil uil-check-circle text-2xl"></i>
|
||||
<div>
|
||||
<h4 class="font-bold text-lg mb-1">{!! t('Ödeme Başarılı!') !!}</h4>
|
||||
<p>{!! session('success') !!}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if(session('error'))
|
||||
<div class="row mb-8">
|
||||
<div class="col-lg-8 mx-auto">
|
||||
<div class="alert alert-danger bg-red-100 text-red-700 border-red-200 rounded-xl p-4 flex items-center gap-3">
|
||||
<i class="uil uil-exclamation-triangle text-2xl"></i>
|
||||
<div>
|
||||
<h4 class="font-bold text-lg mb-1">{!! t('Ödeme Başarısız!') !!}</h4>
|
||||
<p>{!! session('error') !!}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if($errors->any())
|
||||
<div class="row mb-8">
|
||||
<div class="col-lg-8 mx-auto">
|
||||
<div class="alert alert-danger p-4 rounded-xl border border-red-200 bg-red-50" style="background-color: #fef2f2 !important; border-color: #fecaca !important;">
|
||||
<div class="flex items-center gap-3 mb-2" style="color: #dc2626 !important;">
|
||||
<i class="uil uil-exclamation-triangle text-2xl"></i>
|
||||
<h4 class="font-bold text-lg mb-0" style="color: #dc2626 !important;">{!! t('Lütfen Bilgileri Kontrol Ediniz') !!}</h4>
|
||||
</div>
|
||||
<ul class="list-disc pl-10 mb-0 font-medium" style="color: #dc2626 !important;">
|
||||
@foreach ($errors->all() as $error)
|
||||
<li>{{ $error }}</li>
|
||||
@endforeach
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-10 col-xl-9">
|
||||
@if(isset($paytr_token))
|
||||
<div class="card shadow-lg border-0 rounded-3xl overflow-hidden relative" style="min-height: 500px;">
|
||||
<!-- Üst Turuncu Çizgi -->
|
||||
<div class="absolute top-0 left-0 w-full h-2 bg-gradient-to-r from-orange-500 to-amber-500"></div>
|
||||
<div class="card-body p-4 bg-white">
|
||||
<script src="https://www.paytr.com/js/iframeResizer.min.js"></script>
|
||||
<iframe src="https://www.paytr.com/odeme/guvenli/{!! $paytr_token !!}" id="paytriframe" frameborder="0" scrolling="no" style="width: 100%;"></iframe>
|
||||
<script>iFrameResize({},'#paytriframe');</script>
|
||||
</div>
|
||||
</div>
|
||||
@else
|
||||
<div class="card shadow-lg border-0 rounded-3xl overflow-hidden relative">
|
||||
<!-- Üst Turuncu Çizgi -->
|
||||
<div class="absolute top-0 left-0 w-full h-2 bg-gradient-to-r from-orange-500 to-amber-500"></div>
|
||||
|
||||
<div class="card-body p-0">
|
||||
|
||||
|
||||
<form action="{{ route('payment.process') }}" method="POST">
|
||||
@csrf
|
||||
<input type="hidden" name="payment_type" value="online">
|
||||
|
||||
<div class="row g-0">
|
||||
<!-- Sol Taraf: Ödeme Formu -->
|
||||
<div class="col-lg-7 p-8 md:p-10 bg-white">
|
||||
<h3 class="h4 mb-6 text-slate-800 font-bold flex items-center gap-2">
|
||||
<div class="w-8 h-8 rounded-full bg-orange-100 flex items-center justify-center text-orange-600 text-sm">1</div>
|
||||
{!! t('Kart Sahibi Bilgileri') !!}
|
||||
</h3>
|
||||
|
||||
<div class="row g-4">
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="name" class="form-label text-slate-700 font-bold mb-2">{!! t('Adınız') !!}</label>
|
||||
<input type="text" name="name" class="form-control bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-orange-500 focus:border-orange-500 block w-full p-3 @error('name') border-red-500 @enderror" id="name" placeholder="{!! t('Adınızı Giriniz') !!}" value="{{ old('name') }}">
|
||||
@error('name') <div class="text-red-600 text-sm mt-1 font-medium">{{ $message }}</div> @enderror
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="surname" class="form-label text-slate-700 font-bold mb-2">{!! t('Soyadınız') !!}</label>
|
||||
<input type="text" name="surname" class="form-control bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-orange-500 focus:border-orange-500 block w-full p-3 @error('surname') border-red-500 @enderror" id="surname" placeholder="{!! t('Soyadınızı Giriniz') !!}" value="{{ old('surname') }}">
|
||||
@error('surname') <div class="text-red-600 text-sm mt-1 font-medium">{{ $message }}</div> @enderror
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="email" class="form-label text-slate-700 font-bold mb-2">{!! t('E-Posta Adresi') !!}</label>
|
||||
<input type="email" name="email" class="form-control bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-orange-500 focus:border-orange-500 block w-full p-3 @error('email') border-red-500 @enderror" id="email" placeholder="{!! t('E-Posta Adresinizi Giriniz') !!}" value="{{ old('email') }}">
|
||||
@error('email') <div class="text-red-600 text-sm mt-1 font-medium">{{ $message }}</div> @enderror
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="mb-3">
|
||||
<label for="phone" class="form-label text-slate-700 font-bold mb-2">{!! t('Telefon Numarası') !!}</label>
|
||||
<input type="tel" name="phone" class="form-control bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-orange-500 focus:border-orange-500 block w-full p-3 @error('phone') border-red-500 @enderror" id="phone" placeholder="{!! t('Telefon Numaranızı Giriniz') !!}" value="{{ old('phone') }}">
|
||||
@error('phone') <div class="text-red-600 text-sm mt-1 font-medium">{{ $message }}</div> @enderror
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
<div class="mb-3">
|
||||
<label for="address" class="form-label text-slate-700 font-bold mb-2">{!! t('Ödeme Açıklaması / Not') !!}</label>
|
||||
<textarea name="address" class="form-control bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-orange-500 focus:border-orange-500 block w-full p-3 @error('address') border-red-500 @enderror" id="address" placeholder="{!! t('Varsa notunuzu buraya yazabilirsiniz...') !!}" style="height: 100px;">{{ old('address') }}</textarea>
|
||||
@error('address') <div class="text-red-600 text-sm mt-1 font-medium">{{ $message }}</div> @enderror
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-8 pt-6 border-t border-slate-100">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input border-slate-300 checked:bg-orange-500 checked:border-orange-500 focus:ring-orange-200 @error('agreement') border-red-500 @enderror" type="checkbox" name="agreement" value="1" id="policyCheck" {{ old('agreement') ? 'checked' : '' }}>
|
||||
<label class="form-check-label text-sm text-slate-500" for="policyCheck">
|
||||
{!! t('<a href="#" class="text-orange-600 hover:text-orange-700 font-medium">Mesafeli Satış Sözleşmesi</a>\'ni okudum, onaylıyorum.') !!}
|
||||
</label>
|
||||
@error('agreement') <div class="text-red-600 text-sm mt-1 font-medium">{{ $message }}</div> @enderror
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sağ Taraf: Özet ve Tutar -->
|
||||
<div class="col-lg-5 bg-slate-50 p-8 md:p-10 border-l border-slate-100 flex flex-col justify-between">
|
||||
<div>
|
||||
<h3 class="h4 mb-6 text-slate-800 font-bold flex items-center gap-2">
|
||||
<div class="w-8 h-8 rounded-full bg-slate-200 flex items-center justify-center text-slate-600 text-sm">2</div>
|
||||
{!! t('Ödeme Tutarı') !!}
|
||||
</h3>
|
||||
|
||||
<div class="bg-white p-6 rounded-2xl border border-slate-200 shadow-sm text-center mb-6">
|
||||
<label class="block text-xs font-bold text-slate-400 uppercase tracking-wider mb-2">{!! t('TOPLAM TUTAR') !!}</label>
|
||||
<div class="relative inline-block w-full">
|
||||
<span class="absolute left-4 top-1/2 -translate-y-1/2 text-2xl font-bold text-orange-500">₺</span>
|
||||
<input type="number" step="0.01" min="1" name="price" class="form-control border-0 bg-transparent text-center text-4xl font-bold text-slate-800 p-0 focus:ring-0 focus:shadow-none w-full @error('price') text-red-500 @enderror" placeholder="0.00" id="amount" value="{{ old('price') }}">
|
||||
</div>
|
||||
@error('price') <div class="text-red-600 text-xs mt-1 font-medium">{{ $message }}</div> @enderror
|
||||
</div>
|
||||
|
||||
<div class="space-y-3 opacity-70">
|
||||
<div class="flex items-center gap-3 text-sm text-slate-600">
|
||||
<i class="uil uil-check-circle text-green-500 text-lg"></i>
|
||||
<span>{!! t('Komisyonsuz İşlem') !!}</span>
|
||||
</div>
|
||||
<div class="flex items-center gap-3 text-sm text-slate-600">
|
||||
<i class="uil uil-check-circle text-green-500 text-lg"></i>
|
||||
<span>{!! t('3D Secure ile Maksimum Güvenlik') !!}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-8">
|
||||
<button type="submit" class="btn w-full rounded-xl py-3 px-6 text-white font-bold text-lg shadow-lg hover:-translate-y-1 transition-all duration-300 flex items-center justify-center gap-2" style="background-color: #dc2626 !important; color: #ffffff !important; box-shadow: 0 4px 6px -1px rgba(220, 38, 38, 0.5);">
|
||||
<i class="uil uil-padlock"></i>
|
||||
<span>{!! t('ÖDEMEYİ TAMAMLA') !!}</span>
|
||||
</button>
|
||||
|
||||
<div class="mt-6 flex justify-center gap-4 opacity-50 grayscale hover:grayscale-0 transition-all duration-300">
|
||||
<i class="uil uil-master-card text-3xl"></i>
|
||||
<i class="uil uil-visa text-3xl"></i>
|
||||
<i class="uil uil-card-atm text-3xl"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if($page->content)
|
||||
<div class="mt-14 text-center">
|
||||
<div class="prose max-w-3xl mx-auto text-slate-600">
|
||||
{!! $page->content !!}
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@endsection
|
||||
@@ -100,6 +100,11 @@ Route::prefix('admin/api')->middleware(['auth', \App\Http\Middleware\SuperAdminM
|
||||
// Products & Services
|
||||
Route::get('/urun-hizmet/{slug}', [\App\Http\Controllers\ProductController::class, 'show'])->name('products.show');
|
||||
|
||||
// Payment Process
|
||||
Route::post('/payment/process', [\App\Http\Controllers\PaymentController::class, 'process'])->name('payment.process');
|
||||
Route::any('/payment/success', [\App\Http\Controllers\PaymentController::class, 'success'])->name('payment.success');
|
||||
Route::any('/payment/fail', [\App\Http\Controllers\PaymentController::class, 'fail'])->name('payment.fail');
|
||||
|
||||
// Logo Preview
|
||||
Route::get('/logo-preview', function (Illuminate\Http\Request $request) {
|
||||
$path = $request->query('path');
|
||||
|
||||
Reference in New Issue
Block a user