polishing
Some checks failed
linter / quality (push) Failing after 1m2s
tests / ci (8.3) (push) Failing after 47s
tests / ci (8.4) (push) Failing after 1m5s
tests / ci (8.5) (push) Failing after 1m5s

This commit is contained in:
Daan Meijer 2026-06-22 15:21:27 +02:00
parent f3d5be6a80
commit 77c3e34d5b
10 changed files with 52 additions and 10 deletions

View File

@ -13,6 +13,10 @@ class DynamicResource extends BaseResource
*/
public function toArray(Request $request): array
{
return parent::toArray($request);
$result = parent::toArray($request);
if($this->ledgers){
$result['ledgers'] = LedgerResource::collection($this->ledgers);
}
return $result;
}
}

View File

@ -22,4 +22,8 @@ class Chat extends Model
{
return $this->hasMany(Message::class);
}
public function getSubjectUrlAttribute(): string {
return $this->chatable?->url ?? '';
}
}

View File

@ -60,4 +60,8 @@ class Dynamic extends Model
{
return 'uuid';
}
public function getUrlAttribute(): string {
return route('dynamics.show', $this);
}
}

View File

@ -55,4 +55,8 @@ class Ledger extends Model
{
return 'uuid';
}
public function getUrlAttribute(): string {
return route('dynamics.ledgers.show', $this);
}
}

View File

@ -41,4 +41,8 @@ class Message extends Model
{
return $this->morphMany(Media::class, 'mediable');
}
public function getSubjectUrlAttribute(): string {
return $this->subject->url ?? '';
}
}

View File

@ -2,6 +2,8 @@
namespace App\Notifications;
use App\Models\Chat;
use App\Models\Message;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use NotificationChannels\WebPush\WebPushChannel;
@ -36,12 +38,24 @@ class NewActivityNotification extends Notification
*/
public function toWebPush(object $notifiable): WebPushMessage
{
return (new WebPushMessage)
$result = (new WebPushMessage)
->title('New Activity')
->icon('/apple-touch-icon.png')
->body($this->activity['content'])
->action('View', 'view')
->data(['url' => $this->activity['url']]);
switch (get_class($this->activity)) {
case Message::class:
/** @var Chat $chat */
$chat = $this->activity->chat;
$result->data(['url' => $chat->subjectUrl]);
break;
}
return $result;
}
/**

View File

@ -32,7 +32,7 @@ const props = withDefaults(
display_name: string | null;
} | null;
}>;
dynamicId: number;
dynamicId: string;
initialMessages: {
data: Array<any>;
next_page_url: string | null;
@ -92,6 +92,7 @@ useEcho(`chats.${props.chat.id}`, 'MessageSent', (e: any) => {
function formatTimestamp(isoString: string): { full: string; time: string } {
const date = new Date(isoString);
return {
full: date.toLocaleString(),
time: date.toLocaleTimeString([], {
@ -108,6 +109,7 @@ const participantsById = computed(() => {
return list.reduce(
(acc, p) => {
acc[p.id] = p;
return acc;
},
{} as Record<
@ -133,12 +135,15 @@ function parseMessageContent(message: {
const userRegex = /<user:(\d+)>/g;
content = content.replace(userRegex, (match, userId) => {
const user = participantsById.value[Number(userId)];
if (user) {
const url = route('dynamics.users.show', [props.dynamicId, Number(userId)]);
return `<a href="${url}" class="c-chat__user-link font-semibold text-blue-500 hover:underline">${
user.pivot?.display_name ?? user.name
}</a>`;
}
return `User #${userId}`;
});
@ -183,6 +188,7 @@ function parseMessageContent(message: {
function handleFileChange(event: Event) {
const files = (event.target as HTMLInputElement).files;
if (files) {
for (let i = 0; i < files.length; i++) {
form.media.push(files[i]);
@ -200,6 +206,7 @@ function isOwnMessage(messageUserId: number | null): boolean {
if (messageUserId === null) {
return false;
}
return currentUser.value && currentUser.value.id === messageUserId;
}
@ -207,6 +214,7 @@ function submit() {
form.post(route('chats.messages.store', props.chat.id), {
onSuccess: () => {
form.reset();
if (fileInput.value) {
fileInput.value.value = '';
}

View File

@ -3,9 +3,9 @@ import { Link } from '@inertiajs/vue3';
import { route } from 'ziggy-js';
defineProps<{
dynamicId: number;
dynamicId: string;
ledgers: Array<{
id: number;
id: string;
name: string;
score: number;
alignment: string;

View File

@ -3,9 +3,9 @@ import { Link } from '@inertiajs/vue3';
import { route } from 'ziggy-js';
defineProps<{
dynamicId: number;
dynamicId: string;
participants: Array<{
id: number;
id: string;
name: string;
pivot: {
display_name: string | null;

View File

@ -24,7 +24,7 @@ defineOptions({
const props = defineProps<{
dynamic: {
id: number;
id: string;
name: string;
rules: string;
chat: any;
@ -37,7 +37,6 @@ const props = defineProps<{
media?: Array<{ id: number; url: string; mime_type: string }>;
}>;
};
isOwner: boolean;
messages: {
data: Array<any>;
next_page_url: string | null;
@ -90,7 +89,7 @@ const breadcrumbs = [
<!-- Ledgers List Component -->
<LedgerList :dynamic-id="dynamic.id" :ledgers="dynamic.ledgers" />
<div v-if="isOwner" class="mt-8 flex gap-4">
<div v-if="can.update" class="mt-8 flex gap-4">
<InertiaLink :href="route('dynamics.invitations.create', dynamic.id)" class="c-dynamic-show__action-btn">
Invite User
</InertiaLink>
@ -132,6 +131,7 @@ const breadcrumbs = [
.c-dynamic-show__rules {
@apply mt-2 text-sm;
color: var(--muted-foreground);
white-space: pre-line;
}
.c-dynamic-show__settings-btn {