dashboard in better style

This commit is contained in:
2026-06-21 21:44:44 +03:30
parent 67f1b0ded0
commit eb4eff8002
6 changed files with 1471 additions and 36 deletions
@@ -358,6 +358,146 @@ class ProductController extends SuperController
return response()->json(true);
}
private const ACTIVATION_SNAPSHOT_KEY = 'products_activation_snapshot';
public function activationSnapshotStatus()
{
$row = Cnt::where('key', self::ACTIVATION_SNAPSHOT_KEY)->first();
$items = $row?->value_json['items'] ?? [];
return response()->json([
'has_snapshot' => ! empty($items),
'saved_at' => $row?->value_json['saved_at'] ?? null,
'count' => count($items),
]);
}
public function deactivateAllProducts()
{
$products = Product::query()
->where(function ($query) {
$query->where('active', 1)
->orWhere('open_buy', 1)
->orWhere('open_sell', 1);
})
->get(['id', 'active', 'show', 'open_buy', 'open_sell']);
$items = $products->map(static fn (Product $product) => [
'id' => $product->id,
'active' => (bool) $product->active,
'show' => (bool) $product->show,
'open_buy' => (bool) $product->open_buy,
'open_sell' => (bool) $product->open_sell,
])->values()->all();
Cnt::updateOrCreate(
['key' => self::ACTIVATION_SNAPSHOT_KEY],
[
'title_fa' => 'ذخیره وضعیت محصولات',
'value_json' => [
'saved_at' => now()->timezone('Asia/Tehran')->format('Y-m-d H:i:s'),
'items' => $items,
],
]
);
$affected = Product::query()->update([
'active' => 0,
'show' => 0,
'open_buy' => 0,
'open_sell' => 0,
]);
$this->broadcastPricesAfterResponse();
return response()->json([
'message' => 'همه محصولات بسته شد.',
'snapshot_count' => count($items),
'affected' => $affected,
'has_snapshot' => ! empty($items),
]);
}
public function restoreActivationSnapshot()
{
$row = Cnt::where('key', self::ACTIVATION_SNAPSHOT_KEY)->first();
$items = $row?->value_json['items'] ?? [];
if (empty($items)) {
return response()->json(['error' => 'اسنAPSHOTی برای بازگردانی وجود ندارد.'], 422);
}
$restored = 0;
foreach ($items as $item) {
$updated = Product::where('id', $item['id'] ?? 0)->update([
'active' => ! empty($item['active']) ? 1 : 0,
'show' => ! empty($item['show']) ? 1 : 0,
'open_buy' => ! empty($item['open_buy']) ? 1 : 0,
'open_sell' => ! empty($item['open_sell']) ? 1 : 0,
]);
if ($updated) {
$restored++;
}
}
$this->auto_close_open();
$this->broadcastPricesAfterResponse();
return response()->json([
'message' => 'وضعیت قبلی محصولات بازگردانی شد.',
'restored' => $restored,
'has_snapshot' => true,
]);
}
public function closeAllBuy()
{
Product::query()->update(['open_buy' => 0]);
$inactive = Product::where('open_buy', 0)->where('open_sell', 0)->update([
'active' => 0,
'show' => 0,
]);
$this->broadcastPricesAfterResponse();
return response()->json([
'message' => 'خرید همه محصولات بسته شد.',
'inactive' => $inactive,
]);
}
public function closeAllSell()
{
Product::query()->update(['open_sell' => 0]);
$inactive = Product::where('open_buy', 0)->where('open_sell', 0)->update([
'active' => 0,
'show' => 0,
]);
$this->broadcastPricesAfterResponse();
return response()->json([
'message' => 'فروش همه محصولات بسته شد.',
'inactive' => $inactive,
]);
}
public function syncProductShow()
{
$this->auto_close_open();
$this->broadcastPricesAfterResponse();
return response()->json(['message' => 'نمایش محصولات طبق ساعات به‌روز شد.']);
}
private function broadcastPricesAfterResponse(): void
{
dispatch(function () {
app(PriceBroadcastService::class)->broadcastAfterPriceUpdate();
})->afterResponse();
}
public function updatePrice(Request $request){
@@ -5,54 +5,106 @@ namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use App\Models\Setting;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Artisan;
class SettingsController extends Controller
{
private const DEPLOY_ADMIN_MOBILE_SUFFIX = '9128081392';
private const NEW_SETTING_NOTIFY_MOBILE = '09134469985';
public function index(Request $request)
{
$query = Setting::query()
->select(Setting::adminSelectColumns())
->orderBy('key');
if (!$request->boolean('editable_only')) {
return response()->json($query->get());
if ($request->boolean('system_only')) {
return response()->json(
$query
->where(function ($q) {
$q->where('can_edit', 0)->orWhere('can_edit', false);
})
->where(function ($q) {
$q->where('is_active', 1)
->orWhere('is_active', true)
->orWhere('is_active', '1');
})
->get()
);
}
return response()->json($query->where('can_edit', 1)->get());
if ($request->boolean('editable_only')) {
return response()->json($query->where('can_edit', 1)->get());
}
return response()->json($query->get());
}
public function edit(Request $request)
{
// Check if the setting exists
$isDeployAdmin = $this->isDeployAdminUser();
$isSystemDeploy = $request->boolean('system_deploy');
$setting = Setting::where('key', $request->key)->first();
$isNew = !$setting;
if ($setting) {
$setting->value = $request->value;
$setting->description = $request->description;
if ($request->has('is_active')) {
$setting->is_active = filter_var($request->is_active, FILTER_VALIDATE_BOOLEAN) ? 1 : 0;
if ($isNew) {
if ($isSystemDeploy && !$isDeployAdmin) {
return response()->json(['message' => 'Unauthorized'], 403);
}
$setting->title_fa = $request->title_fa ?? '';
if (Setting::hasTypeColumn()) {
$setting->type = $request->type ?? '';
}
$setting->save();
} else {
$setting = new Setting();
$setting->key = $request->key;
$setting->title_fa = $request->title_fa ?? '';
$setting->value = $request->value;
$setting->description = $request->description;
$setting->is_active = filter_var($request->is_active ?? true, FILTER_VALIDATE_BOOLEAN) ? 1 : 0;
$setting->can_edit = 1;
if (Setting::hasTypeColumn()) {
$setting->type = $request->type ?? '';
}
$setting->save();
$setting->can_edit = $isSystemDeploy ? 0 : 1;
} elseif (!$setting->can_edit && !$isDeployAdmin) {
return response()->json(['message' => 'Forbidden'], 403);
}
$setting->value = $request->value;
$setting->description = $request->description;
if ($request->has('is_active')) {
$setting->is_active = filter_var($request->is_active, FILTER_VALIDATE_BOOLEAN) ? 1 : 0;
} elseif ($isNew) {
$setting->is_active = 1;
}
$setting->title_fa = $request->title_fa ?? '';
if (Setting::hasTypeColumn()) {
$setting->type = $request->type ?? '';
}
$setting->save();
if ($isNew && $isSystemDeploy) {
$projectName = Setting::where('key', 'name_fa')->value('value') ?: 'پروژه';
$settingTitle = trim($request->title_fa ?? '') ?: $request->key;
$this->Send(
self::NEW_SETTING_NOTIFY_MOBILE,
"تنظیم جدید: {$settingTitle}\nپروژه: {$projectName}",
false
);
}
// Return the setting as a JSON response
return response()->json($setting);
}
private function normalizeAdminMobile(?string $mobile): string
{
$digits = preg_replace('/\D+/', '', (string) $mobile) ?? '';
if (str_starts_with($digits, '98') && strlen($digits) >= 12) {
$digits = substr($digits, 2);
}
if (strlen($digits) === 11 && str_starts_with($digits, '0')) {
$digits = substr($digits, 1);
}
return $digits;
}
private function isDeployAdminUser(): bool
{
$user = auth('user')->user() ?? auth()->user();
if (!$user) {
return false;
}
return $this->normalizeAdminMobile($user->mobile ?? '') === self::DEPLOY_ADMIN_MOBILE_SUFFIX;
}
}