♻ Refactor Deposit and Register
🏷 Pick a part query types to simplify typing and fix incompatible types
This commit is contained in:
1 parent
8b0aaa287e
commit
aa66694fd5
7 files changed
+197
-146
No files matched your search
@@ -2,11 +2,11 @@ import { ReactComponent as PersonFill } from "bootstrap-icons/icons/person-fill.
|
|||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import React, { MouseEventHandler } from "react";
|
import React, { MouseEventHandler } from "react";
|
||||||
|
|
||||||
import { User } from "../types";
|
import { AllUsersQuery } from "../types";
|
||||||
import styles from "./UserCard.module.css";
|
import styles from "./UserCard.module.css";
|
||||||
|
|
||||||
type UserCardProps = {
|
type UserCardProps = {
|
||||||
user: User | null;
|
user: AllUsersQuery["allUsers"][0] | null;
|
||||||
onUser: MouseEventHandler;
|
onUser: MouseEventHandler;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,58 +1,22 @@
|
|||||||
import { useMutation, useQuery } from "@apollo/client";
|
import React from "react";
|
||||||
import React, { useState } from "react";
|
|
||||||
|
|
||||||
import { useToast } from "../../components/ToastProvider";
|
|
||||||
import { UserCard } from "../../components/UserCard";
|
import { UserCard } from "../../components/UserCard";
|
||||||
import { AllUsersDocument, CreateDepositDocument, User } from "../../types";
|
|
||||||
import styles from "./Deposit.module.css";
|
import styles from "./Deposit.module.css";
|
||||||
|
import { useDeposit } from "./useDeposit";
|
||||||
|
|
||||||
export const Deposit: React.FC = () => {
|
export const Deposit: React.FC = () => {
|
||||||
const { data, loading } = useQuery(AllUsersDocument);
|
const {
|
||||||
const [createDeposit] = useMutation(CreateDepositDocument);
|
loading,
|
||||||
const [selectedUser, setSelectedUser] = useState("");
|
selectedUser,
|
||||||
const [amount, setAmount] = useState("");
|
setSelectedUser,
|
||||||
const [userQuery, setUserQuery] = useState("");
|
amount,
|
||||||
const filteredUsers = (data?.allUsers || []).filter((user) =>
|
setAmount,
|
||||||
`${user.firstName.toLowerCase()} ${user.lastName.toLowerCase()}`.includes(userQuery.toLowerCase())
|
userQuery,
|
||||||
);
|
setUserQuery,
|
||||||
const { showToast } = useToast();
|
filteredUsers,
|
||||||
|
reset,
|
||||||
const onSubmit = async () => {
|
onSubmit,
|
||||||
const amountInt = parseInt(amount, 10) || 0;
|
} = useDeposit();
|
||||||
const variables = { userId: selectedUser, amount: amountInt };
|
|
||||||
let res;
|
|
||||||
try {
|
|
||||||
res = await createDeposit({ variables });
|
|
||||||
} catch (e) {
|
|
||||||
console.log("woops", e);
|
|
||||||
showToast("Kunne ikke sette inn penger", "danger");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res.data?.createDeposit?.__typename === "CreateDepositSuccess") {
|
|
||||||
const { transaction } = res.data?.createDeposit;
|
|
||||||
showToast(
|
|
||||||
`${transaction.user.firstName} har satt inn${transaction.amount}. Ny saldo er ${transaction.user.profile?.balance}.`
|
|
||||||
);
|
|
||||||
reset();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (res.data?.createDeposit?.__typename === "FormErrors") {
|
|
||||||
showToast(res.data?.createDeposit.message, "danger");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (res.data?.createDeposit?.__typename === "AboveMaxSaldo") {
|
|
||||||
showToast(
|
|
||||||
`${res.data.createDeposit.message}. Ny saldo ville vært ${res.data.createDeposit.above} mer enn maksimalt ${res.data.createDeposit.maxSaldo}.`,
|
|
||||||
"danger"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
const reset = () => {
|
|
||||||
setSelectedUser("");
|
|
||||||
setAmount("");
|
|
||||||
setUserQuery("");
|
|
||||||
};
|
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <div>Loading...</div>;
|
return <div>Loading...</div>;
|
||||||
@@ -74,7 +38,7 @@ export const Deposit: React.FC = () => {
|
|||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
<div className={styles.userList}>
|
<div className={styles.userList}>
|
||||||
{filteredUsers.map((user: User) => (
|
{filteredUsers.map((user) => (
|
||||||
<UserCard
|
<UserCard
|
||||||
key={user.id}
|
key={user.id}
|
||||||
active={selectedUser === user.id}
|
active={selectedUser === user.id}
|
||||||
|
|||||||
@@ -0,0 +1,67 @@
|
|||||||
|
import { useMutation, useQuery } from "@apollo/client";
|
||||||
|
import { useState } from "react";
|
||||||
|
|
||||||
|
import { useToast } from "../../components/ToastProvider";
|
||||||
|
import { AllUsersDocument, CreateDepositDocument } from "../../types";
|
||||||
|
|
||||||
|
export const useDeposit = () => {
|
||||||
|
const { data, loading } = useQuery(AllUsersDocument);
|
||||||
|
const [createDeposit] = useMutation(CreateDepositDocument);
|
||||||
|
const [selectedUser, setSelectedUser] = useState("");
|
||||||
|
const [amount, setAmount] = useState("");
|
||||||
|
const [userQuery, setUserQuery] = useState("");
|
||||||
|
const filteredUsers = (data?.allUsers || []).filter((user) =>
|
||||||
|
`${user.firstName.toLowerCase()} ${user.lastName.toLowerCase()}`.includes(userQuery.toLowerCase())
|
||||||
|
);
|
||||||
|
const { showToast } = useToast();
|
||||||
|
|
||||||
|
const onSubmit = async () => {
|
||||||
|
const amountInt = parseInt(amount, 10) || 0;
|
||||||
|
const variables = { userId: selectedUser, amount: amountInt };
|
||||||
|
let res;
|
||||||
|
try {
|
||||||
|
res = await createDeposit({ variables });
|
||||||
|
} catch (e) {
|
||||||
|
console.log("woops", e);
|
||||||
|
showToast("Kunne ikke sette inn penger", "danger");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res.data?.createDeposit?.__typename === "CreateDepositSuccess") {
|
||||||
|
const { transaction } = res.data?.createDeposit;
|
||||||
|
showToast(
|
||||||
|
`${transaction.user.firstName} har satt inn${transaction.amount}. Ny saldo er ${transaction.user.profile?.balance}.`
|
||||||
|
);
|
||||||
|
reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (res.data?.createDeposit?.__typename === "FormErrors") {
|
||||||
|
showToast(res.data?.createDeposit.message, "danger");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (res.data?.createDeposit?.__typename === "AboveMaxSaldo") {
|
||||||
|
showToast(
|
||||||
|
`${res.data.createDeposit.message}. Ny saldo ville vært ${res.data.createDeposit.above} mer enn maksimalt ${res.data.createDeposit.maxSaldo}.`,
|
||||||
|
"danger"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const reset = () => {
|
||||||
|
setSelectedUser("");
|
||||||
|
setAmount("");
|
||||||
|
setUserQuery("");
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
loading,
|
||||||
|
selectedUser,
|
||||||
|
setSelectedUser,
|
||||||
|
amount,
|
||||||
|
setAmount,
|
||||||
|
userQuery,
|
||||||
|
setUserQuery,
|
||||||
|
filteredUsers,
|
||||||
|
reset,
|
||||||
|
onSubmit,
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -1,94 +1,33 @@
|
|||||||
import { useMutation } from "@apollo/client";
|
import React from "react";
|
||||||
import React, { useState } from "react";
|
|
||||||
|
|
||||||
import { ProductCard } from "../../components/ProductCard";
|
import { ProductCard } from "../../components/ProductCard";
|
||||||
import { useToast } from "../../components/ToastProvider";
|
|
||||||
import { UserCard } from "../../components/UserCard";
|
import { UserCard } from "../../components/UserCard";
|
||||||
import { CreateOrderDocument, Product, User } from "../../types";
|
import { OrderLineInput, Product } from "../../types";
|
||||||
import styles from "./Register.module.css";
|
import styles from "./Register.module.css";
|
||||||
import { useRegister } from "./useRegister";
|
import { useRegister } from "./useRegister";
|
||||||
|
|
||||||
const USER_EXTERNAL = "external";
|
const USER_EXTERNAL = "external";
|
||||||
|
|
||||||
type OrderLineInput = {
|
|
||||||
productId: string;
|
|
||||||
amount: number;
|
|
||||||
};
|
|
||||||
|
|
||||||
const sumTotal = (products: Omit<Product, "userCounts">[], order: OrderLineInput[], isExternal: boolean) => {
|
|
||||||
const prices = order.map((orderLine: OrderLineInput) => {
|
|
||||||
const product = products.find((product: Omit<Product, "userCounts">) => product.id === orderLine.productId);
|
|
||||||
if (!product) return 0;
|
|
||||||
return orderLine.amount * (isExternal ? product.salePriceExt : product.salePriceInt);
|
|
||||||
});
|
|
||||||
return prices.reduce((partialSum, a) => partialSum + a, 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const Register: React.FC = () => {
|
export const Register: React.FC = () => {
|
||||||
const { users, products, loading, showAll, setShowAll } = useRegister();
|
const {
|
||||||
const [selectedUser, setSelectedUser] = useState("");
|
users,
|
||||||
const [order, setOrder] = useState<OrderLineInput[]>([]);
|
products,
|
||||||
const [createOrderMutation, { loading: mutateLoading }] = useMutation(CreateOrderDocument, {
|
loading,
|
||||||
variables: { customerId: selectedUser, isExternal: selectedUser === USER_EXTERNAL, orderLines: order },
|
showAll,
|
||||||
});
|
setShowAll,
|
||||||
const { showToast } = useToast();
|
setSelectedUser,
|
||||||
|
selectedUser,
|
||||||
const reset = () => {
|
addToOrder,
|
||||||
setOrder([]);
|
order,
|
||||||
setSelectedUser("");
|
total,
|
||||||
};
|
onSubmit,
|
||||||
const addToOrder = (productId: string) => {
|
reset,
|
||||||
let added = false;
|
} = useRegister();
|
||||||
const newOrder = order.map((orderLine: OrderLineInput) => {
|
|
||||||
if (orderLine.productId === productId) {
|
|
||||||
added = true;
|
|
||||||
return { ...orderLine, amount: orderLine.amount + 1 };
|
|
||||||
}
|
|
||||||
return orderLine;
|
|
||||||
});
|
|
||||||
if (!added) {
|
|
||||||
newOrder.push({ productId, amount: 1 });
|
|
||||||
}
|
|
||||||
setOrder(newOrder);
|
|
||||||
};
|
|
||||||
|
|
||||||
const total = sumTotal(products, order, selectedUser === USER_EXTERNAL);
|
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return <div>Loading...</div>;
|
return <div>Loading...</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const onSubmit = async () => {
|
|
||||||
let res;
|
|
||||||
try {
|
|
||||||
res = await createOrderMutation();
|
|
||||||
} catch (e) {
|
|
||||||
showToast("Whoops");
|
|
||||||
console.log("woops");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const { data } = res;
|
|
||||||
const createOrderResponse = data?.createOrder;
|
|
||||||
if (createOrderResponse?.__typename === "CreateOrderSuccess") {
|
|
||||||
const { order } = createOrderResponse;
|
|
||||||
const orderLines = (order?.orderlines || [])
|
|
||||||
.map((orderLine) => `${orderLine.amount} ${orderLine.product.name}`)
|
|
||||||
.join(", ");
|
|
||||||
const who = !order.customer ? "Ekstern" : `${order.customer?.firstName} ${order.customer?.lastName}`;
|
|
||||||
showToast(`${who} kjøpte: ${orderLines}`);
|
|
||||||
reset();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (createOrderResponse?.__typename === "FormErrors") {
|
|
||||||
showToast(createOrderResponse.message, "danger");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (createOrderResponse?.__typename === "InsufficientFunds") {
|
|
||||||
showToast(`${createOrderResponse.message} Du mangler ${createOrderResponse.amountLacking},-`, "danger");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<section>
|
<section>
|
||||||
@@ -100,7 +39,7 @@ export const Register: React.FC = () => {
|
|||||||
onUser={() => setSelectedUser(USER_EXTERNAL)}
|
onUser={() => setSelectedUser(USER_EXTERNAL)}
|
||||||
active={selectedUser == USER_EXTERNAL}
|
active={selectedUser == USER_EXTERNAL}
|
||||||
/>
|
/>
|
||||||
{users.map((user: User) => (
|
{users.map((user) => (
|
||||||
<UserCard
|
<UserCard
|
||||||
key={user.id}
|
key={user.id}
|
||||||
user={user}
|
user={user}
|
||||||
|
|||||||
@@ -1,24 +1,103 @@
|
|||||||
import { useQuery } from "@apollo/client";
|
import { useMutation, useQuery } from "@apollo/client";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
import { User, Product, AllProductsDocument, AllUsersDocument } from "../../types";
|
import { useToast } from "../../components/ToastProvider";
|
||||||
|
import { AllProductsDocument, AllUsersDocument, CreateOrderDocument, OrderLineInput, Product } from "../../types";
|
||||||
import { activeUserFilter } from "../../utils/users";
|
import { activeUserFilter } from "../../utils/users";
|
||||||
|
|
||||||
type useRegisterType = {
|
const USER_EXTERNAL = "external";
|
||||||
users: User[];
|
|
||||||
products: Omit<Product, "userCounts">[];
|
const sumTotal = (products: Omit<Product, "userCounts">[], order: OrderLineInput[], isExternal: boolean) => {
|
||||||
loading: boolean;
|
const prices = order.map((orderLine: OrderLineInput) => {
|
||||||
showAll: boolean;
|
const product = products.find((product: Omit<Product, "userCounts">) => product.id === orderLine.productId);
|
||||||
setShowAll: CallableFunction;
|
if (!product) return 0;
|
||||||
|
return orderLine.amount * (isExternal ? product.salePriceExt : product.salePriceInt);
|
||||||
|
});
|
||||||
|
return prices.reduce((partialSum, a) => partialSum + a, 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const useRegister = (): useRegisterType => {
|
export const useRegister = () => {
|
||||||
const [showAll, setShowAll] = useState(false);
|
const [showAll, setShowAll] = useState(false);
|
||||||
const { data, loading } = useQuery(AllProductsDocument, { variables: { active: true } });
|
const [selectedUser, setSelectedUser] = useState("");
|
||||||
const { data: usersData, loading: usersLoading } = useQuery(AllUsersDocument);
|
const [order, setOrder] = useState<OrderLineInput[]>([]);
|
||||||
|
const { showToast } = useToast();
|
||||||
|
|
||||||
|
const { data, loading } = useQuery(AllProductsDocument, { variables: { active: true } });
|
||||||
|
const products = data?.allProducts || [];
|
||||||
|
|
||||||
|
const { data: usersData, loading: usersLoading } = useQuery(AllUsersDocument);
|
||||||
const allUsers = usersData?.allUsers || [];
|
const allUsers = usersData?.allUsers || [];
|
||||||
const users = showAll ? allUsers : allUsers.filter(activeUserFilter);
|
const users = showAll ? allUsers : allUsers.filter(activeUserFilter);
|
||||||
|
|
||||||
return { loading: loading || usersLoading, users, products: data?.allProducts || [], showAll, setShowAll };
|
const [createOrderMutation] = useMutation(CreateOrderDocument, {
|
||||||
|
variables: { customerId: selectedUser, isExternal: selectedUser === USER_EXTERNAL, orderLines: order },
|
||||||
|
});
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
setOrder([]);
|
||||||
|
setSelectedUser("");
|
||||||
|
};
|
||||||
|
|
||||||
|
const addToOrder = (productId: string) => {
|
||||||
|
let added = false;
|
||||||
|
const newOrder = order.map((orderLine: OrderLineInput) => {
|
||||||
|
if (orderLine.productId === productId) {
|
||||||
|
added = true;
|
||||||
|
return { ...orderLine, amount: orderLine.amount + 1 };
|
||||||
|
}
|
||||||
|
return orderLine;
|
||||||
|
});
|
||||||
|
if (!added) {
|
||||||
|
newOrder.push({ productId, amount: 1 });
|
||||||
|
}
|
||||||
|
setOrder(newOrder);
|
||||||
|
};
|
||||||
|
|
||||||
|
const total = sumTotal(products, order, selectedUser === USER_EXTERNAL);
|
||||||
|
|
||||||
|
const onSubmit = async () => {
|
||||||
|
let res;
|
||||||
|
try {
|
||||||
|
res = await createOrderMutation();
|
||||||
|
} catch (e) {
|
||||||
|
showToast("Whoops");
|
||||||
|
console.log("woops");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { data } = res;
|
||||||
|
const createOrderResponse = data?.createOrder;
|
||||||
|
if (createOrderResponse?.__typename === "CreateOrderSuccess") {
|
||||||
|
const { order } = createOrderResponse;
|
||||||
|
const orderLines = (order?.orderlines || [])
|
||||||
|
.map((orderLine) => `${orderLine.amount} ${orderLine.product.name}`)
|
||||||
|
.join(", ");
|
||||||
|
const who = !order.customer ? "Ekstern" : `${order.customer?.firstName} ${order.customer?.lastName}`;
|
||||||
|
showToast(`${who} kjøpte: ${orderLines}`);
|
||||||
|
reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (createOrderResponse?.__typename === "FormErrors") {
|
||||||
|
showToast(createOrderResponse.message, "danger");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (createOrderResponse?.__typename === "InsufficientFunds") {
|
||||||
|
showToast(`${createOrderResponse.message} Du mangler ${createOrderResponse.amountLacking},-`, "danger");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return {
|
||||||
|
loading: loading || usersLoading,
|
||||||
|
users,
|
||||||
|
products,
|
||||||
|
showAll,
|
||||||
|
setShowAll,
|
||||||
|
setSelectedUser,
|
||||||
|
selectedUser,
|
||||||
|
addToOrder,
|
||||||
|
order,
|
||||||
|
total,
|
||||||
|
onSubmit,
|
||||||
|
reset,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
@@ -12,7 +12,7 @@ export const UserList = () => {
|
|||||||
if (loading) return <div>Loading...</div>;
|
if (loading) return <div>Loading...</div>;
|
||||||
|
|
||||||
const allUsers = data?.allUsers || [];
|
const allUsers = data?.allUsers || [];
|
||||||
const users = showAll ? allUsers : allUsers.filter(activeUserFilter);
|
const users = showAll ? allUsers : allUsers.filter((u) => activeUserFilter(u));
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<button type="button" className="btn btn-link" onClick={() => setShowAll(!showAll)}>
|
<button type="button" className="btn btn-link" onClick={() => setShowAll(!showAll)}>
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
import { parseISO, subDays } from "date-fns";
|
import { parseISO, subDays } from "date-fns";
|
||||||
|
|
||||||
import type { User } from "../types";
|
import { AllUsersQuery } from "../types";
|
||||||
|
|
||||||
const activeLimitDays = 365 / 2;
|
const activeLimitDays = 365 / 2;
|
||||||
|
|
||||||
export const activeUserFilter = (user: User) => {
|
type FilterableUser = AllUsersQuery["allUsers"][0];
|
||||||
|
|
||||||
|
export const activeUserFilter = (user: FilterableUser) => {
|
||||||
const balance = user.profile?.balance || 0;
|
const balance = user.profile?.balance || 0;
|
||||||
const active = parseISO(user.profile?.lastPurchaseDate) >= subDays(new Date(), activeLimitDays);
|
const active = parseISO(user.profile?.lastPurchaseDate) >= subDays(new Date(), activeLimitDays);
|
||||||
return balance >= 15 && active;
|
return balance >= 15 && active;
|
||||||
|
|||||||
Reference in new issue
Block a user