summaryrefslogtreecommitdiff
path: root/app/components/FilterBar.tsx
blob: f897e67ea0a36ffbc1f6555004b049faf1827cc2 (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
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
import { Form, useSearchParams } from "react-router";
import type { Venue } from "~/lib/db.server";

interface Props {
  venues: Venue[];
  areas?: string[];
  defaultDateFrom?: string;
  defaultDateTo?: string;
  /** Show the "favorites only" toggle (logged in only) */
  showFavorites?: boolean;
}

export default function FilterBar({ venues, areas, defaultDateFrom, defaultDateTo, showFavorites }: Props) {
  const [searchParams] = useSearchParams();

  return (
    <Form method="get" className="flex flex-wrap gap-3 items-end">
      {/* Keyword */}
      <div className="flex flex-col gap-1">
        <label className="text-xs text-gray-400">キーワード</label>
        <input
          name="keyword"
          type="text"
          defaultValue={searchParams.get("keyword") ?? ""}
          placeholder="アーティスト名、イベント名..."
          className="rounded-md bg-gray-800 border border-gray-700 px-3 py-1.5 text-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 w-full sm:w-52"
        />
      </div>

      {/* Venue */}
      <div className="flex flex-col gap-1">
        <label className="text-xs text-gray-400">会場</label>
        <select
          name="venue_id"
          defaultValue={searchParams.get("venue_id") ?? ""}
          className="rounded-md bg-gray-800 border border-gray-700 px-3 py-1.5 text-sm focus:outline-none focus:ring-1 focus:ring-indigo-500"
        >
          <option value="">すべて</option>
          {venues.map((v) => (
            <option key={v.id} value={v.id}>
              {v.name}
            </option>
          ))}
        </select>
      </div>

      {/* Date from */}
      <div className="flex flex-col gap-1">
        <label className="text-xs text-gray-400">開始日</label>
        <input
          name="date_from"
          type="date"
          defaultValue={searchParams.get("date_from") ?? defaultDateFrom ?? ""}
          className="rounded-md bg-gray-800 border border-gray-700 px-3 py-1.5 text-sm focus:outline-none focus:ring-1 focus:ring-indigo-500"
        />
      </div>

      {/* Date to */}
      <div className="flex flex-col gap-1">
        <label className="text-xs text-gray-400">終了日</label>
        <input
          name="date_to"
          type="date"
          defaultValue={searchParams.get("date_to") ?? defaultDateTo ?? ""}
          className="rounded-md bg-gray-800 border border-gray-700 px-3 py-1.5 text-sm focus:outline-none focus:ring-1 focus:ring-indigo-500"
        />
      </div>

      {/* Area */}
      {areas && areas.length > 0 && (
        <div className="flex flex-col gap-1">
          <label className="text-xs text-gray-400">エリア</label>
          <select
            name="area"
            defaultValue={searchParams.get("area") ?? ""}
            className="rounded-md bg-gray-800 border border-gray-700 px-3 py-1.5 text-sm focus:outline-none focus:ring-1 focus:ring-indigo-500"
          >
            <option value="">すべて</option>
            {areas.map((a) => (
              <option key={a} value={a}>
                {a}
              </option>
            ))}
          </select>
        </div>
      )}

      {/* Capacity */}
      <div className="flex flex-col gap-1">
        <label className="text-xs text-gray-400">キャパシティ</label>
        <select
          name="capacity_range"
          defaultValue={searchParams.get("capacity_range") ?? ""}
          className="rounded-md bg-gray-800 border border-gray-700 px-3 py-1.5 text-sm focus:outline-none focus:ring-1 focus:ring-indigo-500"
        >
          <option value="">すべて</option>
          <option value="small">〜100人(小箱)</option>
          <option value="medium">100〜300人(中箱)</option>
          <option value="large">300人〜(大箱)</option>
        </select>
      </div>

      {showFavorites && (
        <label className="flex items-center gap-1.5 py-1.5 text-sm text-gray-300 cursor-pointer">
          <input
            name="fav"
            type="checkbox"
            value="1"
            defaultChecked={searchParams.get("fav") === "1"}
            className="accent-amber-400"
          />
          <span className="text-amber-400">★</span> お気に入りのみ
        </label>
      )}

      <button
        type="submit"
        className="rounded-md bg-gray-700 px-4 py-1.5 text-sm font-medium hover:bg-gray-600 transition-colors"
      >
        絞り込む
      </button>

      {hasFilters(searchParams) && (
        <a
          href="/events"
          className="rounded-md border border-gray-700 px-4 py-1.5 text-sm text-gray-400 hover:text-white transition-colors"
        >
          クリア
        </a>
      )}
    </Form>
  );
}

function hasFilters(params: URLSearchParams): boolean {
  return ["keyword", "venue_id", "date_from", "date_to", "capacity_range", "area", "fav"].some((k) => params.get(k));
}