summaryrefslogtreecommitdiff
path: root/app/components/EventCard.tsx
blob: 6651ff9fe03671d619ab0e485bc704e393cff92e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
import { Link } from "react-router";
import type { Event } from "~/lib/db.server";

interface Props {
  event: Event;
}

export default function EventCard({ event }: Props) {
  const formattedDate = formatDate(event.date);
  const timeLabel = buildTimeLabel(event.open_time, event.start_time);

  return (
    <Link
      to={`/events/${event.id}`}
      className="group flex flex-col rounded-xl bg-gray-800/60 border border-gray-700/40 overflow-hidden hover:border-indigo-500/60 hover:bg-gray-800 transition-all"
    >
      {event.image_url ? (
        <img
          src={event.image_url}
          alt={event.title}
          className="h-36 w-full object-cover"
        />
      ) : (
        <div className="h-36 w-full bg-gradient-to-br from-gray-800 to-gray-900 flex items-center justify-center">
          <span className="text-4xl opacity-20">🎸</span>
        </div>
      )}

      <div className="flex-1 p-4 flex flex-col gap-2">
        {/* Title */}
        <h2 className="font-semibold text-sm leading-snug group-hover:text-indigo-300 transition-colors line-clamp-2">
          {event.title}
        </h2>

        {/* Artist — required */}
        <p className="text-xs text-indigo-300 font-medium line-clamp-1">
          {event.artist ?? "出演者未定"}
        </p>

        {/* Date + time */}
        <div className="flex items-center gap-2 text-xs text-gray-300">
          <span>📅 {formattedDate}</span>
          {timeLabel && <span className="text-gray-500">| {timeLabel}</span>}
        </div>

        {/* Venue */}
        <div className="flex items-center gap-1 text-xs text-gray-400">
          <span>📍</span>
          <span className="rounded-full bg-gray-700/60 px-2 py-0.5">
            {event.venue_name}
            {event.venue_area ? `(${event.venue_area})` : ""}
          </span>
        </div>

        {/* Fee */}
        {event.price && (
          <p className="text-xs text-emerald-400">¥ {event.price}</p>
        )}

        {/* Ticket URL */}
        {event.ticket_url && (
          <a
            href={event.ticket_url}
            target="_blank"
            rel="noopener noreferrer"
            onClick={(e) => e.stopPropagation()}
            className="mt-auto inline-flex items-center gap-1 text-xs text-indigo-400 hover:underline"
          >
            🎟 チケット
          </a>
        )}
      </div>
    </Link>
  );
}

function formatDate(iso: string): string {
  const [y, m, d] = iso.split("-");
  const days = ["日", "月", "火", "水", "木", "金", "土"];
  const dayIdx = new Date(`${iso}T00:00:00`).getDay();
  return `${y}/${m}/${d}(${days[dayIdx]})`;
}

function buildTimeLabel(open: string | null, start: string | null): string {
  const parts: string[] = [];
  if (open) parts.push(`OPEN ${open}`);
  if (start) parts.push(`START ${start}`);
  return parts.join(" / ");
}