Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 31 additions & 4 deletions view-admin/src/components/common/JudgementModal/JudgementModal.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import React, { useMemo, useState } from "react";
import { useLazyQuery } from "@apollo/client";
import styles from "./JudgementModal.module.css";
import { RxCrossCircled, RxCross1 } from "react-icons/rx";
import { GiPartyPopper } from "react-icons/gi";

import { SubscribeListNumbersSubscription } from "@/type/graphql";
import {
SubscribeListNumbersSubscription,
GetListNumbersDocument,
GetListNumbersQuery,
} from "@/type/graphql";

type BingoCard = string[][];
type CellPos = { row: number; col: number };
Expand Down Expand Up @@ -115,6 +120,11 @@ const JudgementModal = ({
const [inputValue, setInputValue] = useState("");
const [hasJudged, setHasJudged] = useState(false);
const [completedLines, setCompletedLines] = useState<LineId[]>([]);
// network-only: キャッシュを参照せず、毎回ネットワークから取得。取得結果はキャッシュに書き込み
const [getLatestNumbers, { loading: isGettingLatest }] =
useLazyQuery<GetListNumbersQuery>(GetListNumbersDocument, {
fetchPolicy: "network-only",
});

// 抽選済みの数字一覧
const drawnNumbers = useMemo(
Expand Down Expand Up @@ -159,13 +169,26 @@ const JudgementModal = ({
};

// ビンゴ判定
const handleJudge = () => {
const handleJudge = async () => {
let numbersForJudgement = drawnNumbers;
try {
const res = await getLatestNumbers();
const latest = res.data?.numbers ?? [];
if (latest.length > 0) {
numbersForJudgement = latest.map((n) => n.number);
}
} catch (_) {
// 取得失敗時は subscription 由来の値でフォールバック
console.warn(
"[JudgementModal] 最新番号の取得に失敗したため、subscriptionの値で判定を継続します。",
);
}
const workingCard = finalizePendingInput(false);

const done: LineId[] = [];
for (const line of ALL_LINES) {
const ok = line.cells.every(({ row, col }) =>
isCellSatisfied(workingCard[row][col], drawnNumbers),
isCellSatisfied(workingCard[row][col], numbersForJudgement),
);
if (ok) done.push(line.id);
}
Expand Down Expand Up @@ -356,7 +379,11 @@ const JudgementModal = ({
</div>

<div className={styles.actionButtonsContainer}>
<button onClick={handleJudge} className={styles.submitButton}>
<button
onClick={handleJudge}
className={styles.submitButton}
disabled={isGettingLatest}
>
ビンゴ判定
</button>
<button onClick={resetAll} className={styles.resetButton}>
Expand Down
45 changes: 44 additions & 1 deletion view-admin/src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import {
ApolloClient,
InMemoryCache,
HttpLink,
split,
} from "@apollo/client";
import { getMainDefinition } from "@apollo/client/utilities";
import { GraphQLWsLink } from "@apollo/client/link/subscriptions";
import { createClient } from "graphql-ws";
import { SessionProvider } from "next-auth/react";
Expand All @@ -25,9 +27,50 @@ const wsClient = createClient({
// ヘッダーを含んだ websocket リンクを作成
const wsLink = new GraphQLWsLink(wsClient);

// HTTP リンク(query/mutation 用): API_URI が未設定の場合は WS_API_URL から http(s) を推測してフォールバック
const resolveHttpGraphqlUri = () => {
const apiBase = process.env.API_URI;
if (apiBase) return apiBase.replace(/\/$/, "") + "/v1/graphql";
const wsBase = process.env.WS_API_URL;
if (wsBase) {
try {
const u = new URL(wsBase);
u.protocol = u.protocol === "wss:" ? "https:" : "http:";
u.pathname = "/v1/graphql";
return u.toString();
} catch (_) {
// noop
}
}
console.error(
"[Apollo] API_URI が未設定で、WS_API_URL からのフォールバックにも失敗しました。/v1/graphql にフォールバックします。",
);
return "/v1/graphql";
};

const httpLink = new HttpLink({
uri: resolveHttpGraphqlUri(),
headers: {
"x-hasura-admin-secret": process.env.HASURA_GRAPHQL_ADMIN_SECRET as string,
},
});

// subscription は WS、それ以外は HTTP
const splitLink = split(
({ query }) => {
const definition = getMainDefinition(query);
return (
definition.kind === "OperationDefinition" &&
definition.operation === "subscription"
);
},
wsLink,
httpLink,
);

// Apollo client を作成
const client = new ApolloClient({
link: wsLink,
link: splitLink,
cache: new InMemoryCache(),
});

Expand Down