mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-05-05 20:56:13 -05:00
Merge branch 'css-rework-sidenav' of https://github.com/sendou-ink/sendou.ink into css-rework-sidenav
This commit is contained in:
parent
445cb38b6c
commit
a9d797f552
|
|
@ -3,12 +3,15 @@ import { ArrowLeft, MessageSquare, X } from "lucide-react";
|
|||
import { Button } from "react-aria-components";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router";
|
||||
import { resolveDatePlaceholders } from "~/features/chat/chat-utils";
|
||||
import { Chat } from "~/features/chat/components/Chat";
|
||||
import { useChatContext } from "~/features/chat/useChatContext";
|
||||
import { useTimeFormat } from "~/hooks/useTimeFormat";
|
||||
import sideNavStyles from "../SideNav.module.css";
|
||||
import styles from "./ChatSidebar.module.css";
|
||||
|
||||
// xxx: add navIcon/url per room
|
||||
|
||||
export function ChatSidebar({ onClose }: { onClose?: () => void }) {
|
||||
const chatContext = useChatContext();
|
||||
|
||||
|
|
@ -94,7 +97,14 @@ function RoomList({ onClose }: { onClose?: () => void }) {
|
|||
styles.roomName,
|
||||
)}
|
||||
>
|
||||
{room.header}
|
||||
{resolveDatePlaceholders(room.header, (d) =>
|
||||
formatDateTime(d, {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
}),
|
||||
)}
|
||||
</span>
|
||||
<span className={sideNavStyles.listLinkSubtitle}>
|
||||
{room.subtitle}
|
||||
|
|
@ -122,6 +132,7 @@ function RoomList({ onClose }: { onClose?: () => void }) {
|
|||
function ChatView({ onClose }: { onClose?: () => void }) {
|
||||
const chatContext = useChatContext()!;
|
||||
const activeRoom = chatContext.activeRoom!;
|
||||
const { formatDateTime } = useTimeFormat();
|
||||
|
||||
const otherRoomsUnreadCount = Object.entries(chatContext.unreadCounts)
|
||||
.filter(([code]) => code !== activeRoom)
|
||||
|
|
@ -147,7 +158,14 @@ function ChatView({ onClose }: { onClose?: () => void }) {
|
|||
const headerContent = (
|
||||
<>
|
||||
<span className={styles.chatHeaderTitle}>
|
||||
{room?.header ?? activeRoom}
|
||||
{resolveDatePlaceholders(room?.header ?? activeRoom, (d) =>
|
||||
formatDateTime(d, {
|
||||
month: "short",
|
||||
day: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
}),
|
||||
)}
|
||||
</span>
|
||||
{room?.subtitle ? (
|
||||
<span className={styles.chatHeaderSubtitle}>{room.subtitle}</span>
|
||||
|
|
|
|||
44
app/features/chat/chat-utils.test.ts
Normal file
44
app/features/chat/chat-utils.test.ts
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
import { describe, expect, test } from "vitest";
|
||||
import { datePlaceholder, resolveDatePlaceholders } from "./chat-utils";
|
||||
|
||||
describe("datePlaceholder", () => {
|
||||
test("returns correctly formatted placeholder string", () => {
|
||||
const date = new Date(1700000000000);
|
||||
|
||||
expect(datePlaceholder(date)).toBe("{{date:1700000000000}}");
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveDatePlaceholders", () => {
|
||||
const mockFormat = (d: Date) => `FORMATTED:${d.getTime()}`;
|
||||
|
||||
test("replaces a single placeholder with formatted date", () => {
|
||||
const text = "Starts at {{date:1700000000000}}";
|
||||
|
||||
expect(resolveDatePlaceholders(text, mockFormat)).toBe(
|
||||
"Starts at FORMATTED:1700000000000",
|
||||
);
|
||||
});
|
||||
|
||||
test("replaces multiple placeholders in one string", () => {
|
||||
const text = "From {{date:1700000000000}} to {{date:1700003600000}}";
|
||||
|
||||
expect(resolveDatePlaceholders(text, mockFormat)).toBe(
|
||||
"From FORMATTED:1700000000000 to FORMATTED:1700003600000",
|
||||
);
|
||||
});
|
||||
|
||||
test("returns text unchanged when no placeholders present", () => {
|
||||
const text = "Just a normal string";
|
||||
|
||||
expect(resolveDatePlaceholders(text, mockFormat)).toBe(text);
|
||||
});
|
||||
|
||||
test("handles text that is only a placeholder", () => {
|
||||
const text = "{{date:1700000000000}}";
|
||||
|
||||
expect(resolveDatePlaceholders(text, mockFormat)).toBe(
|
||||
"FORMATTED:1700000000000",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,5 +1,20 @@
|
|||
import type { ChatMessage } from "./chat-types";
|
||||
|
||||
const DATE_PLACEHOLDER_PATTERN = /\{\{date:(\d+)\}\}/g;
|
||||
|
||||
export function datePlaceholder(date: Date): string {
|
||||
return `{{date:${date.getTime()}}}`;
|
||||
}
|
||||
|
||||
export function resolveDatePlaceholders(
|
||||
text: string,
|
||||
formatDateTime: (date: Date) => string,
|
||||
): string {
|
||||
return text.replace(DATE_PLACEHOLDER_PATTERN, (_match, ts) =>
|
||||
formatDateTime(new Date(Number(ts))),
|
||||
);
|
||||
}
|
||||
|
||||
export function messageTypeToSound(type: ChatMessage["type"]) {
|
||||
if (type === "LIKE_RECEIVED") return "sq_like";
|
||||
if (type === "MATCH_STARTED") return "sq_match";
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import type { ActionFunctionArgs } from "react-router";
|
|||
import { redirect } from "react-router";
|
||||
import { requireUser } from "~/features/auth/core/user.server";
|
||||
import * as ChatSystemMessage from "~/features/chat/ChatSystemMessage.server";
|
||||
import { datePlaceholder } from "~/features/chat/chat-utils";
|
||||
import { notify } from "~/features/notifications/core/notify.server";
|
||||
import * as UserRepository from "~/features/user-page/UserRepository.server";
|
||||
import { requirePermission } from "~/modules/permissions/guards.server";
|
||||
|
|
@ -113,9 +114,10 @@ export const action = async ({ request }: ActionFunctionArgs) => {
|
|||
if (fullPost?.chatCode) {
|
||||
ChatSystemMessage.setMetadata({
|
||||
chatCode: fullPost.chatCode,
|
||||
header: "Scrim",
|
||||
// xxx: better subtitle?
|
||||
subtitle: `Scrim #${post.id}`,
|
||||
header: datePlaceholder(
|
||||
databaseTimestampToDate(request.at ?? post.at),
|
||||
),
|
||||
subtitle: "Scrim",
|
||||
url: scrimPage(post.id),
|
||||
participantUserIds: Scrim.participantIdsListFromAccepted(fullPost),
|
||||
expiresAt: add(databaseTimestampToDate(request.at ?? post.at), {
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user