Skip to content

Commit

Permalink
オーダーストップの情報をグローバルに共有
Browse files Browse the repository at this point in the history
  • Loading branch information
toririm committed Oct 30, 2024
1 parent 7a27e88 commit cd2ebb1
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 36 deletions.
27 changes: 11 additions & 16 deletions common/firebase-utils/converter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,14 @@ import {
Timestamp,
} from "firebase/firestore";
import _ from "lodash";
import type { ZodSchema } from "zod";
import type { WithId } from "../lib/typeguard";
import {
type GlobalCashierState,
MasterStateEntity,
globalStatSchema,
} from "models/global";
import type { ZodSchema } from "zod";
import type { WithId } from "../lib/typeguard";
globalCashierStateSchema,
globalMasterStateSchema,
} from "../models/global";
import { ItemEntity, itemSchema } from "../models/item";
import { OrderEntity, orderSchema } from "../models/order";

Expand Down Expand Up @@ -103,37 +104,31 @@ export const orderConverter: FirestoreDataConverter<WithId<OrderEntity>> = {

export const cashierStateConverter: FirestoreDataConverter<GlobalCashierState> =
{
toFirestore: converter(globalStatSchema).toFirestore,
toFirestore: converter(globalCashierStateSchema).toFirestore,
fromFirestore: (
snapshot: QueryDocumentSnapshot,
options: SnapshotOptions,
) => {
const convertedData = converter(globalStatSchema).fromFirestore(
const convertedData = converter(globalCashierStateSchema).fromFirestore(
snapshot,
options,
);

if (convertedData.id === "cashier-state") {
return convertedData;
}
throw new Error("Invalid data");
return convertedData;
},
};

export const masterStateConverter: FirestoreDataConverter<MasterStateEntity> = {
toFirestore: converter(globalStatSchema).toFirestore,
toFirestore: converter(globalMasterStateSchema).toFirestore,
fromFirestore: (
snapshot: QueryDocumentSnapshot,
options: SnapshotOptions,
) => {
const convertedData = converter(globalStatSchema).fromFirestore(
const convertedData = converter(globalMasterStateSchema).fromFirestore(
snapshot,
options,
);

if (convertedData.id === "master-state") {
return MasterStateEntity.fromMasterState(convertedData);
}
throw new Error("Invalid data");
return MasterStateEntity.fromMasterState(convertedData);
},
};
23 changes: 23 additions & 0 deletions common/firebase-utils/subscription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
type FirestoreDataConverter,
type QueryConstraint,
collection,
doc,
onSnapshot,
query,
} from "firebase/firestore";
Expand Down Expand Up @@ -34,3 +35,25 @@ export const collectionSub = <T>(
};
return sub;
};

export const documentSub = <T>({
converter,
}: { converter: FirestoreDataConverter<T> }) => {
const sub: SWRSubscription<string[], T, Error> = (
[collectionName, ...keys],
{ next },
) => {
const coll = collection(prodDB, collectionName);
const unsub = onSnapshot(
doc(coll, ...keys).withConverter(converter),
(snapshot) => {
next(null, snapshot.data());
},
(err) => {
next(err);
},
);
return unsub;
};
return sub;
};
20 changes: 12 additions & 8 deletions common/models/global.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { z } from "zod";
import { orderSchema } from "./order";

export const GlobalCashierStateSchema = z.object({
export const globalCashierStateSchema = z.object({
id: z.literal("cashier-state"),
edittingOrder: orderSchema,
});

export type GlobalCashierState = z.infer<typeof GlobalCashierStateSchema>;
export type GlobalCashierState = z.infer<typeof globalCashierStateSchema>;

const orderStatTypes = ["stop", "operational"] as const;
export const orderStatTypes = ["stop", "operational"] as const;

export const orderStatSchema = z.object({
createdAt: z.date(),
Expand All @@ -18,16 +18,16 @@ export const orderStatSchema = z.object({
export type OrderStatType = (typeof orderStatTypes)[number];
export type OrderStat = z.infer<typeof orderStatSchema>;

export const GlobalMasterStateSchema = z.object({
export const globalMasterStateSchema = z.object({
id: z.literal("master-state"),
orderStats: z.array(orderStatSchema),
});

export type GlobalMasterState = z.infer<typeof GlobalMasterStateSchema>;
export type GlobalMasterState = z.infer<typeof globalMasterStateSchema>;

export const globalStatSchema = z.union([
GlobalCashierStateSchema,
GlobalMasterStateSchema,
globalCashierStateSchema,
globalMasterStateSchema,
]);

export type GlobalStat = z.infer<typeof globalStatSchema>;
Expand All @@ -43,7 +43,11 @@ export class MasterStateEntity implements GlobalMasterState {
}

static createNew(): MasterStateEntity {
return new MasterStateEntity("master-state", []);
const initOrderStat: OrderStat = {
createdAt: new Date(),
type: "operational",
};
return new MasterStateEntity("master-state", [initOrderStat]);
}

get orderStats() {
Expand Down
8 changes: 4 additions & 4 deletions common/repositories/global.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { type Firestore, doc, getDoc, setDoc } from "firebase/firestore";
import {
cashierStateConverter,
masterStateConverter,
} from "firebase-utils/converter";
import { prodDB } from "firebase-utils/firestore";
import { type Firestore, doc, getDoc, setDoc } from "firebase/firestore";
import type { GlobalCashierState, MasterStateEntity } from "models/global";
} from "../firebase-utils/converter";
import { prodDB } from "../firebase-utils/firestore";
import type { GlobalCashierState, MasterStateEntity } from "../models/global";

export type CashierStateRepo = {
get: () => Promise<GlobalCashierState | undefined>;
Expand Down
4 changes: 2 additions & 2 deletions firestore.rules
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ service cloud.firestore {
match /orders/{orderId} {
allow read, write: if true;
}
match /global/{document=**} {
match /global/{docId} {
allow read, write: if true;
}
}
}
}
93 changes: 87 additions & 6 deletions pos/app/routes/_header.master.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,28 @@ import {
useSubmit,
} from "@remix-run/react";
import { id2abbr } from "common/data/items";
import { orderConverter } from "common/firebase-utils/converter";
import { collectionSub } from "common/firebase-utils/subscription";
import {
masterStateConverter,
orderConverter,
} from "common/firebase-utils/converter";
import { collectionSub, documentSub } from "common/firebase-utils/subscription";
import { stringToJSONSchema } from "common/lib/custom-zod";
import {
MasterStateEntity,
type OrderStatType,
orderStatTypes,
} from "common/models/global";
import { OrderEntity, orderSchema } from "common/models/order";
import { masterRepository } from "common/repositories/global";
import { orderRepository } from "common/repositories/order";
import dayjs from "dayjs";
import { orderBy } from "firebase/firestore";
import { useCallback } from "react";
import { useCallback, useMemo } from "react";
import useSWRSubscription from "swr/subscription";
import { z } from "zod";
import { InputComment } from "~/components/molecules/InputComment";
import { RealtimeElapsedTime } from "~/components/molecules/RealtimeElapsedTime";
import { Button } from "~/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "~/components/ui/card";
import { cn } from "~/lib/utils";

Expand All @@ -37,6 +47,22 @@ export default function FielsOfMaster() {
},
[submit],
);
const { data: masterRemoStat } = useSWRSubscription(
["global", "master-state"],
documentSub({ converter: masterStateConverter }),
);
const masterStat = masterRemoStat ?? MasterStateEntity.createNew();
const orderStat = useMemo(() => {
const state = masterStat.orderStats[masterStat.orderStats.length - 1];
return state.type;
}, [masterStat]);

const changeOrderStat = useCallback(
(status: OrderStatType) => {
submit({ status }, { method: "POST" });
},
[submit],
);

const { data: orders } = useSWRSubscription(
"orders",
Expand All @@ -54,6 +80,20 @@ export default function FielsOfMaster() {
<div className="p-4 font-sans">
<div className="flex justify-between pb-4">
<h1 className="text-3xl">マスター</h1>
<Button
type="submit"
className={cn(
orderStat === "operational" ? "bg-red-700" : "bg-sky-700",
)}
onClick={() =>
changeOrderStat(
orderStat === "operational" ? "stop" : "operational",
)
}
>
{orderStat === "operational" && "オーダーストップする"}
{orderStat === "stop" && "オーダー再開する"}
</Button>
<p>提供待ちオーダー数:{unserved}</p>
</div>

Expand All @@ -79,8 +119,8 @@ export default function FielsOfMaster() {
</CardHeader>
<CardContent>
<div className="mb-4 grid grid-cols-2 gap-2">
{order.items.map((item) => (
<div key={item.id}>
{order.items.map((item, index) => (
<div key={`${order.id}-${index}-${item.id}`}>
<Card
className={cn(
"pt-6",
Expand Down Expand Up @@ -132,7 +172,20 @@ export default function FielsOfMaster() {
);
}

export const clientAction: ClientActionFunction = async ({ request }) => {
// TODO: ファイル分割してリファクタリングする
export const clientAction: ClientActionFunction = async (args) => {
const method = args.request.method;
switch (method) {
case "PUT":
return addComment(args);
case "POST":
return changeOrderStat(args);
default:
throw new Error(`Method ${method} is not allowed`);
}
};

export const addComment: ClientActionFunction = async ({ request }) => {
const formData = await request.formData();

const schema = z.object({
Expand All @@ -155,3 +208,31 @@ export const clientAction: ClientActionFunction = async ({ request }) => {

return new Response("ok");
};

export const changeOrderStat: ClientActionFunction = async ({ request }) => {
const formData = await request.formData();

const schema = z.object({
status: z.enum(orderStatTypes),
});
const submission = parseWithZod(formData, {
schema,
});
if (submission.status !== "success") {
console.error(submission.error);
return submission.reply();
}

const { status } = submission.value;

const masterStats: MasterStateEntity =
(await masterRepository.get()) ?? MasterStateEntity.createNew();

console.log(status);
masterStats.addOrderStat(status);
console.log(masterStats);

await masterRepository.set(masterStats);

return new Response("ok");
};

0 comments on commit cd2ebb1

Please sign in to comment.