diff --git a/.env.example b/.env.example index b7c73320d..792fe0262 100644 --- a/.env.example +++ b/.env.example @@ -4,6 +4,8 @@ APP_KEY= APP_DEBUG=true APP_URL=http://localhost APP_DOMAIN=localhost +APP_TIMEZONE=UTC +DISPLAY_TIMEZONE=America/Sao_Paulo NIGHTWATCH_TOKEN= LOG_CHANNEL=stack diff --git a/app-modules/bot-discord/src/Events/GreetingsEvent.php b/app-modules/bot-discord/src/Events/GreetingsEvent.php index d95f3f72d..6cb53645c 100644 --- a/app-modules/bot-discord/src/Events/GreetingsEvent.php +++ b/app-modules/bot-discord/src/Events/GreetingsEvent.php @@ -27,7 +27,7 @@ public function handle(Message $message, Discord $discord): void return; } - $hour = now()->hour; + $hour = now()->timezone(config('app.display_timezone'))->hour; $payload = mb_strtolower($message->content); $response = match (true) { diff --git a/app-modules/he4rt/resources/views/components/dashboard/heatmap.blade.php b/app-modules/he4rt/resources/views/components/dashboard/heatmap.blade.php index 3b6f76382..ec68053e2 100644 --- a/app-modules/he4rt/resources/views/components/dashboard/heatmap.blade.php +++ b/app-modules/he4rt/resources/views/components/dashboard/heatmap.blade.php @@ -152,8 +152,8 @@ }; // Now indicator - $nowRow = $highlightNow && $isWeek ? (int) now()->format('N') - 1 : -1; - $nowCol = $highlightNow && $isWeek ? (int) now()->format('G') : -1; + $nowRow = $highlightNow && $isWeek ? (int) now(config('app.display_timezone'))->format('N') - 1 : -1; + $nowCol = $highlightNow && $isWeek ? (int) now(config('app.display_timezone'))->format('G') : -1; // Auto insight $autoHeadline = $insightHeadline; diff --git a/app-modules/he4rt/resources/views/components/schedule-card.blade.php b/app-modules/he4rt/resources/views/components/schedule-card.blade.php index f2a8870e5..ad68b1bb5 100644 --- a/app-modules/he4rt/resources/views/components/schedule-card.blade.php +++ b/app-modules/he4rt/resources/views/components/schedule-card.blade.php @@ -1,15 +1,12 @@ -@props([ - 'startsAt', - 'endsAt', - 'title', - 'icon', - 'speakers', -]) +@props (['startsAt', 'endsAt', 'title', 'icon', 'speakers']) @php /** @var \Carbon\Carbon $startsAt */ /** @var \Carbon\Carbon $endsAt */ + $startsAt = $startsAt->timezone(config('app.display_timezone')); + $endsAt = $endsAt->timezone(config('app.display_timezone')); + $config = match (true) { $endsAt->isPast() => [ 'color' => 'text-green-300', @@ -51,7 +48,7 @@ @if ($speakers) - // {{ $speakers->map(fn ($speaker) => $speaker->name)->implode(', ') }} \\ + // {{ $speakers->map(fn($speaker) => $speaker->name)->implode(', ') }} \\ @endif diff --git a/app-modules/integration-discord/src/ETL/Console/BackfillVoiceLogsCommand.php b/app-modules/integration-discord/src/ETL/Console/BackfillVoiceLogsCommand.php index 771e1a18e..40715104c 100644 --- a/app-modules/integration-discord/src/ETL/Console/BackfillVoiceLogsCommand.php +++ b/app-modules/integration-discord/src/ETL/Console/BackfillVoiceLogsCommand.php @@ -143,7 +143,7 @@ public function handle( foreach ($messages as $message) { $timestamp = CarbonImmutable::parse($message['timestamp']); - $oldestTimestamp = $timestamp->format('Y-m-d H:i'); + $oldestTimestamp = $timestamp->timezone(config('app.display_timezone'))->format('Y-m-d H:i'); if ($timestamp->isBefore($since)) { $reachedSince = true; @@ -181,7 +181,7 @@ public function handle( $this->alreadyExistsCount++; $logger->line(sprintf( '%s <@%s> %s #%s [EXISTS]', - $timestamp->format('m/d H:i'), + $timestamp->timezone(config('app.display_timezone'))->format('m/d H:i'), $voiceDto->userDiscordId, $voiceDto->action, $channelName, @@ -201,7 +201,7 @@ public function handle( $logger->line(sprintf( '%s <@%s> %s #%s [NEW]', - $timestamp->format('m/d H:i'), + $timestamp->timezone(config('app.display_timezone'))->format('m/d H:i'), $voiceDto->userDiscordId, $voiceDto->action, $channelName, diff --git a/app-modules/panel-admin/resources/views/moderation/appeal-queue/appeal-detail.blade.php b/app-modules/panel-admin/resources/views/moderation/appeal-queue/appeal-detail.blade.php index 5933e9079..25a3d2586 100644 --- a/app-modules/panel-admin/resources/views/moderation/appeal-queue/appeal-detail.blade.php +++ b/app-modules/panel-admin/resources/views/moderation/appeal-queue/appeal-detail.blade.php @@ -86,7 +86,11 @@ class="mb-4 flex items-start gap-2.5 rounded-lg border border-red-300/40 bg-red- }}

- {{ __('panel-admin::moderation.appeal_queue.detail.sla_deadline') }}: {{ $appeal->sla_deadline->format('M d, Y H:i') }} + {{ __('panel-admin::moderation.appeal_queue.detail.sla_deadline') }}: {{ + $appeal->sla_deadline + ->timezone(config('app.display_timezone')) + ->format('M d, Y H:i') + }}

@@ -381,7 +385,11 @@ class="mb-3 flex items-center gap-2 text-[11px] font-semibold tracking-wider tex 'text-zinc-700 dark:text-zinc-300' => !$isOverdue ]) > - {{ $appeal->sla_deadline?->format('M d, Y H:i') ?? '—' }} + {{ + $appeal->sla_deadline + ?->timezone(config('app.display_timezone')) + ->format('M d, Y H:i') ?? '—' + }} @if ($appeal->sla_deadline && !$appeal->status->isResolved())
*/ public function get(): Collection { - $start = Date::now('America/Sao_Paulo')->subDays($this->rangeDays)->startOfDay()->utc(); + $tz = config('app.display_timezone'); + $start = Date::now($tz)->subDays($this->rangeDays)->startOfDay()->utc(); return DB::table('messages') - ->selectRaw("(sent_at AT TIME ZONE 'UTC' AT TIME ZONE 'America/Sao_Paulo')::date AS day") + ->selectRaw('(sent_at AT TIME ZONE ?)::date AS day', [$tz]) ->selectRaw('COUNT(*) AS total_messages') ->selectRaw('COUNT(DISTINCT external_identity_id) AS unique_users') ->where('sent_at', '>=', $start) diff --git a/app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/MessageHeatmap.php b/app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/MessageHeatmap.php index 732afb570..aff6633e4 100644 --- a/app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/MessageHeatmap.php +++ b/app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/MessageHeatmap.php @@ -16,11 +16,12 @@ public function __construct( /** @return array */ public function get(): array { - $start = Date::now('America/Sao_Paulo')->subDays($this->rangeDays)->startOfDay()->utc(); + $tz = config('app.display_timezone'); + $start = Date::now($tz)->subDays($this->rangeDays)->startOfDay()->utc(); return DB::table('messages') - ->selectRaw("EXTRACT(DOW FROM sent_at AT TIME ZONE 'UTC' AT TIME ZONE 'America/Sao_Paulo')::int AS dow") - ->selectRaw("EXTRACT(HOUR FROM sent_at AT TIME ZONE 'UTC' AT TIME ZONE 'America/Sao_Paulo')::int AS hour") + ->selectRaw('EXTRACT(DOW FROM sent_at AT TIME ZONE ?)::int AS dow', [$tz]) + ->selectRaw('EXTRACT(HOUR FROM sent_at AT TIME ZONE ?)::int AS hour', [$tz]) ->selectRaw('COUNT(*) AS total') ->where('sent_at', '>=', $start) ->whereNotNull('sent_at') diff --git a/app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/PeriodStats.php b/app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/PeriodStats.php index 053c02400..fbd16c240 100644 --- a/app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/PeriodStats.php +++ b/app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/PeriodStats.php @@ -182,7 +182,7 @@ private function queryVoiceStats(array $subdivisions): array private function subdivisions(): array { return once(function (): array { - $now = Date::now('America/Sao_Paulo'); + $now = Date::now(config('app.display_timezone')); [$blockCount, $blockSize, $unit] = match (true) { $this->rangeDays >= 90 => [3, 30, 'days'], diff --git a/app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/TopChannels.php b/app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/TopChannels.php index e503b4584..f4791aa7a 100644 --- a/app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/TopChannels.php +++ b/app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/TopChannels.php @@ -17,7 +17,8 @@ public function __construct( /** @return Collection */ public function get(): Collection { - $start = Date::now('America/Sao_Paulo')->subDays($this->rangeDays)->startOfDay()->utc(); + $tz = config('app.display_timezone'); + $start = Date::now($tz)->subDays($this->rangeDays)->startOfDay()->utc(); return DB::table('messages') ->select('channel_id') diff --git a/app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/VoiceHeatmap.php b/app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/VoiceHeatmap.php index c25b1d2b3..d7b770976 100644 --- a/app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/VoiceHeatmap.php +++ b/app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/VoiceHeatmap.php @@ -16,11 +16,12 @@ public function __construct( /** @return array */ public function get(): array { - $start = Date::now('America/Sao_Paulo')->subDays($this->rangeDays)->startOfDay()->utc(); + $tz = config('app.display_timezone'); + $start = Date::now($tz)->subDays($this->rangeDays)->startOfDay()->utc(); return DB::table('voice_messages') - ->selectRaw("EXTRACT(DOW FROM occurred_at AT TIME ZONE 'America/Sao_Paulo')::int AS dow") - ->selectRaw("EXTRACT(HOUR FROM occurred_at AT TIME ZONE 'America/Sao_Paulo')::int AS hour") + ->selectRaw('EXTRACT(DOW FROM occurred_at AT TIME ZONE ?)::int AS dow', [$tz]) + ->selectRaw('EXTRACT(HOUR FROM occurred_at AT TIME ZONE ?)::int AS hour', [$tz]) ->selectRaw('COUNT(*) AS total') ->where('occurred_at', '>=', $start) ->whereNotNull('occurred_at') diff --git a/app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/VoicePerDay.php b/app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/VoicePerDay.php index f1a854be3..9cf832b5d 100644 --- a/app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/VoicePerDay.php +++ b/app-modules/panel-admin/src/Marketing/Pages/Discord/Dashboard/Queries/VoicePerDay.php @@ -17,10 +17,11 @@ public function __construct( /** @return Collection */ public function get(): Collection { - $start = Date::now('America/Sao_Paulo')->subDays($this->rangeDays)->startOfDay()->utc(); + $tz = config('app.display_timezone'); + $start = Date::now($tz)->subDays($this->rangeDays)->startOfDay()->utc(); return DB::table('voice_messages') - ->selectRaw("(occurred_at AT TIME ZONE 'America/Sao_Paulo')::date AS day") + ->selectRaw('(occurred_at AT TIME ZONE ?)::date AS day', [$tz]) ->selectRaw('COUNT(*) AS total_joins') ->where('occurred_at', '>=', $start) ->whereNotNull('occurred_at') diff --git a/app-modules/panel-admin/src/Marketing/Pages/MeetingShowcasePage.php b/app-modules/panel-admin/src/Marketing/Pages/MeetingShowcasePage.php index 816ff04f9..123a5a0e0 100644 --- a/app-modules/panel-admin/src/Marketing/Pages/MeetingShowcasePage.php +++ b/app-modules/panel-admin/src/Marketing/Pages/MeetingShowcasePage.php @@ -55,8 +55,9 @@ public function loadParticipants(): void return; } - $start = Date::parse($this->startDate, 'America/Sao_Paulo')->utc(); - $end = Date::parse($this->endDate, 'America/Sao_Paulo')->utc(); + $tz = config('app.display_timezone'); + $start = Date::parse($this->startDate, $tz)->utc(); + $end = Date::parse($this->endDate, $tz)->utc(); $messageStats = Message::query() ->where('channel_id', $this->channelId) diff --git a/app-modules/panel-admin/src/Moderation/Livewire/ModerationDashboardLivewire.php b/app-modules/panel-admin/src/Moderation/Livewire/ModerationDashboardLivewire.php index 60753438c..560a2baae 100644 --- a/app-modules/panel-admin/src/Moderation/Livewire/ModerationDashboardLivewire.php +++ b/app-modules/panel-admin/src/Moderation/Livewire/ModerationDashboardLivewire.php @@ -346,10 +346,14 @@ public function repeatOffenders(): Collection #[Computed] public function activityHeatmap(): array { + $tz = config('app.display_timezone'); + $dbData = DB::table('moderation_actions') ->where('created_at', '>=', now()->subDays(30)) - ->selectRaw('EXTRACT(DOW FROM created_at) as dow, EXTRACT(HOUR FROM created_at) as hour, count(*) as total') - ->groupByRaw('EXTRACT(DOW FROM created_at), EXTRACT(HOUR FROM created_at)') + ->selectRaw('EXTRACT(DOW FROM created_at AT TIME ZONE ?)::int AS dow', [$tz]) + ->selectRaw('EXTRACT(HOUR FROM created_at AT TIME ZONE ?)::int AS hour', [$tz]) + ->selectRaw('COUNT(*) AS total') + ->groupBy('dow', 'hour') ->get(); $grid = array_fill(0, 7, array_fill(0, 24, 0)); diff --git a/config/app.php b/config/app.php index c7c3d80b7..5310b707c 100644 --- a/config/app.php +++ b/config/app.php @@ -69,7 +69,9 @@ | */ - 'timezone' => env('APP_TIMEZONE', 'America/Sao_Paulo'), + 'timezone' => env('APP_TIMEZONE', 'UTC'), + + 'display_timezone' => env('DISPLAY_TIMEZONE', 'America/Sao_Paulo'), /* |-------------------------------------------------------------------------- diff --git a/database/migrations/2026_05_20_160249_alter_messages_sent_at_to_timestamptz.php b/database/migrations/2026_05_20_160249_alter_messages_sent_at_to_timestamptz.php new file mode 100644 index 000000000..c5a07a33a --- /dev/null +++ b/database/migrations/2026_05_20_160249_alter_messages_sent_at_to_timestamptz.php @@ -0,0 +1,14 @@ + @foreach ($supportedProviders as $provider) @php - $connectedProvider = $userProviders->filter(fn (ExternalIdentity $connection) => $connection->provider == $provider->value)->first(); + $connectedProvider = $userProviders + ->filter(fn(ExternalIdentity $connection) => $connection->provider == $provider->value) + ->first(); @endphp -
@@ -30,13 +28,15 @@ Connected @endif
-

- {{ $provider->getDescription() }} -

+

{{ $provider->getDescription() }}

@if ($connectedProvider) Connected at - {{ $connectedProvider->updated_at->format('d/m/Y H:i:s') }} + {{ + $connectedProvider->updated_at + ->timezone(config('app.display_timezone')) + ->format('d/m/Y H:i:s') + }} @else Nessa autenticação iremos pedir acesso à: @foreach ($provider->getScopes() as $scope) @@ -48,7 +48,7 @@ {{ $connectedProvider ? 'Disconnect' : 'Connect' }} diff --git a/routes/console.php b/routes/console.php index b439472c3..d610bd88b 100644 --- a/routes/console.php +++ b/routes/console.php @@ -23,4 +23,5 @@ Schedule::command('backup:monitor') ->when(fn () => config('backup.enabled')) ->daily() - ->at('09:00'); + ->at('09:00') + ->timezone(config('app.display_timezone'));