Skip to content

Commit

Permalink
refactor: add types to APIService
Browse files Browse the repository at this point in the history
  • Loading branch information
ivorscott committed Nov 9, 2023
1 parent b7eb06f commit bc4f4b6
Show file tree
Hide file tree
Showing 8 changed files with 115 additions and 91 deletions.
115 changes: 66 additions & 49 deletions src/features/Account/Account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,97 +14,114 @@ import { formatPath } from "../../helpers/helpers";
import { useSubscriptionInfo } from "../../hooks/subscription";
import { client as api } from "../../services/APIService";
import { Intent } from "../../types/intent";
import { Billing } from "./Billing";
import { Modal as AddUser } from "./Modal";
import { SubscriptionInfoSection } from "./SubscriptionInfoSection";
import { columns } from "./TableColumns";
import { components } from "./TableRow";
import { UpgradeModal } from "./UpgradeModal";

interface UserInfoState {
company: string;
tenantId: string;
}

interface TabPanelProps {
children?: React.ReactNode;
index: number;
value: number;
}

interface StripeOptionsState {
clientSecret: string;
}

interface PaymentIntentData {
currency: string;
amount: number;
}

enum AccountTab {
Plan = "plan",
Users = "users",
}

const getTabIndex = (tab: string | null): number => {
if (tab == null) {
tab = AccountTab.Users;
}
let index = 0;
switch (tab) {
case AccountTab.Plan:
break;
case AccountTab.Users:
index = 1;
break;
}
return index;
};

// Make sure to call `loadStripe` outside of a component’s render to avoid
// recreating the `Stripe` object on every render.
const stripePromise = loadStripe(`${process.env.REACT_APP_STRIPE_KEY}`);

export const Account = () => {
const [userInfo, setUserInfo] = useState<{
company: string;
tenantId: string;
}>();
const [value, setValue] = React.useState(0);
const [userInfo, setUserInfo] = useState<UserInfoState>();
const [tabValue, setTab] = React.useState<number>(0);
const [isOpen, setOpen] = useState(false);
const [options, setOptions] = useState<{ clientSecret: string }>();
const [options, setOptions] = useState<StripeOptionsState>();

const [searchParams] = useSearchParams();
const seatsResult = useSeatsAvailable();
const navigate = useNavigate();
const result = useUsers();
const users = useTableUsers(result);
const info = useSubscriptionInfo(userInfo?.tenantId);
const info = useSubscriptionInfo();

const tab = searchParams.get("t");
const basePath = "/" + formatPath(userInfo?.company);

const getTabIndex = (tab: string | null): number => {
if (tab == null) {
tab = AccountTab.Users;
}
let index = 0;
switch (tab) {
case AccountTab.Plan:
break;
case AccountTab.Users:
index = 1;
break;
}
return index;
};

const handleChange = (event: React.SyntheticEvent) => {
const button = event.target as HTMLButtonElement;
if (AccountTab.Users == button.innerText.toLowerCase()) {
const path = `${basePath}/account?t=${AccountTab.Users}`;
const basePath = "/" + formatPath(userInfo?.company);

if (AccountTab.Plan == button.innerText.toLowerCase()) {
const path = `${basePath}/account?t=${AccountTab.Plan}`;
navigate(path);
setTab(0);
} else {
const path = `${basePath}/account?t=${AccountTab.Plan}`;
const path = `${basePath}/account?t=${AccountTab.Users}`;
navigate(path);
setTab(1);
}
};

const toggleModal = () => {
setOpen(!isOpen);
};

useEffect(() => {
const fn = async (tab: string | null) => {
const pi = (await api.post("/subscriptions/payment-intent", {
currency: "eur",
amount: 1000,
})) as Intent;

setOptions({ clientSecret: pi.client_secret });

// get company
const fn = async () => {
const pi = await api.post<PaymentIntentData, Intent>(
"/subscriptions/payment-intent",
{
currency: "eur",
amount: 1000,
}
);
const session = await Auth.currentSession();
return { pi, session };
};

fn().then(({ pi, session }) => {
const data = session.getIdToken().payload;
const company = data["custom:company-name"];
const tenantId = data["custom:tenant-id"];
setOptions({ clientSecret: pi.client_secret });
setUserInfo({ company, tenantId });
setValue(getTabIndex(tab));
};
fn(tab);
setTab(getTabIndex(tab));
});
}, [tab]);

function CustomTabPanel(props: TabPanelProps) {
const toggleModal = () => {
setOpen(!isOpen);
};

const CustomTabPanel = (props: TabPanelProps) => {
const { children, value, index, ...other } = props;

return (
Expand All @@ -118,7 +135,7 @@ export const Account = () => {
{value === index && <Box>{children}</Box>}
</div>
);
}
};

return (
<Layout>
Expand All @@ -138,18 +155,18 @@ export const Account = () => {
<Box sx={{ borderBottom: 1, borderColor: "divider" }}>
<Tabs
onChange={handleChange}
value={value}
value={tabValue}
aria-label="basic tabs example"
>
<Tab label={AccountTab.Plan} />
<Tab label={AccountTab.Users} />
</Tabs>
</Box>
<CustomTabPanel value={value} index={0}>
<CustomTabPanel value={tabValue} index={0}>
{seatsResult.maxSeats == 3 ? (
<>
<h2>Basic Plan</h2>
{info && <SubscriptionInfoSection {...info} />}
{info && <Billing {...info} />}
<StyledPremiumButton variant="contained" onClick={toggleModal}>
Upgrade to Premium
</StyledPremiumButton>
Expand All @@ -168,7 +185,7 @@ export const Account = () => {
<h2>Premium Plan</h2>
)}
</CustomTabPanel>
<CustomTabPanel value={value} index={1}>
<CustomTabPanel value={tabValue} index={1}>
<StyledTable
columns={columns}
data={users}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { PremiumPlan } from "./constants";
import { transactionColumns } from "./TableColumns";
import { components } from "./TableRow";

export const SubscriptionInfoSection = (props: SubscriptionInfo) => {
export const Billing = (props: SubscriptionInfo) => {
return (
<div>
{props.defaultPaymentMethod ? (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { useParams } from "react-router-dom";
import { client as api } from "services/APIService";
import { Project } from "types/project";

import { useProject } from "../../../../../hooks/project";

interface AddTaskProps {
isCreating: boolean;
toggleCreating: () => void;
Expand Down Expand Up @@ -65,11 +67,7 @@ export const AddTask = ({
onAddTask,
}: AddTaskProps) => {
const { id } = useParams();
const { data: selected } = useQuery<Project, AxiosError>(
["project", id],
async () => await api.get(`/projects/${id}`)
);

const { data: selected } = useProject(id);
const [task, setTask] = useState("");

const handleSubmit = () => {
Expand Down
20 changes: 13 additions & 7 deletions src/hooks/board.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,20 @@ import { client as api } from "services/APIService";
import { AddTask, Column, DeleteTask, MoveTask, Task } from "types/board";

export function useColumns(projectId: string) {
return useQuery<Column[], Error>(["project", projectId, "columns"], () => {
return api.get(`/projects/${projectId}/columns`);
});
return useQuery<Column[], Error>(
["project", projectId, "columns"],
(): Promise<Column[]> => {
return api.get(`/projects/${projectId}/columns`);
}
);
}
export function useTasks(projectId: string) {
return useQuery<Task[], Error>(["project", projectId, "tasks"], () => {
return api.get(`/projects/${projectId}/tasks`);
});
return useQuery<Task[], Error>(
["project", projectId, "tasks"],
(): Promise<Task[]> => {
return api.get(`/projects/${projectId}/tasks`);
}
);
}

export function useAddTask() {
Expand Down Expand Up @@ -60,7 +66,7 @@ export function useDeleteTask() {

const { mutate } = useMutation<Task, Error, DeleteTask>(
({ columnId, taskId }) =>
api.delete(`/projects/columns/${columnId}/tasks/${taskId}`),
api.delete<Task>(`/projects/columns/${columnId}/tasks/${taskId}`),
{
onSuccess: (_, variables) => {
queryClient.setQueryData<Task[]>(
Expand Down
9 changes: 4 additions & 5 deletions src/hooks/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@ import { client as api } from "services/APIService";
import { Project } from "types/project";

export function useProject(projectId: string | undefined) {
return useQuery<Project, Error>(
["project", projectId],
async () => await api.get(`/projects/${projectId}`)
return useQuery<Project, Error>(["project", projectId], async () =>
api.get<Project>(`/projects/${projectId}`)
);
}

export function useProjects() {
return useQuery<Project[], Error>(
"projects",
async () => await api.get("/projects")
async () => await api.get<Project[]>("/projects")
);
}

Expand Down Expand Up @@ -63,7 +62,7 @@ export function useUpdateProject() {

export function useDeleteProject() {
const queryClient = useQueryClient();
const { mutate } = useMutation<null, Error, string>(
const { mutate } = useMutation<void, Error, string>(
(id) => api.delete(`/projects/${id}`),
{
onSuccess: async (_, projectId) => {
Expand Down
14 changes: 7 additions & 7 deletions src/hooks/subscription.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Auth } from "aws-amplify";
import { useMutation, useQuery } from "react-query";

import { client as api } from "../services/APIService";
Expand All @@ -9,14 +10,13 @@ export function useCreateSubscription() {
);
}

export function useSubscriptionInfo(tenantId?: string) {
export function useSubscriptionInfo() {
const { isLoading, isError, data } = useQuery<SubscriptionInfo, Error>(
"billing",
async () => {
if (!tenantId) {
return;
}
return api.get(`/subscriptions/${tenantId}`);
"subscriptions",
async (): Promise<SubscriptionInfo> => {
const session = await Auth.currentSession();
const { payload } = session.getIdToken();
return api.get(`/subscriptions/${payload["custom:tenant-id"]}`);
}
);

Expand Down
16 changes: 10 additions & 6 deletions src/hooks/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,14 @@ import {
export function useUser() {
const { isLoading, isError, data } = useQuery<CurrentUser, Error>(
"auth",
async () => {
const data = await api.get("/users/me");
async (): Promise<CurrentUser> => {
const data = await api.get<User>("/users/me");
const session = await Auth.currentSession();
const { payload } = session.getIdToken();

return {
...data,
tenantId: payload["custom:tenantId"],
company: payload["custom:company-name"],
username: payload["cognito:username"],
emailVerified: payload["email_verified"],
Expand Down Expand Up @@ -72,8 +73,8 @@ export function useDeleteUser() {
const queryClient = useQueryClient();

return useMutation<void, Error, DeleteUserInput>(
async ({ userId }) => {
return api.delete(`/users/${userId}`);
async (d): Promise<void> => {
return await api.delete(`/users/${d.userId}`);
},
{
onSuccess: async (_, userId) => {
Expand All @@ -89,12 +90,15 @@ export function useDeleteUser() {
}

export function useUsers() {
return useQuery<User[], Error>("users", async () => await api.get("/users"));
return useQuery<User[], Error>(
"users",
async () => await api.get<User[]>("/users")
);
}

export function useSeatsAvailable() {
const result = useQuery<SeatsAvailable, Error>("seats", async () => {
return await api.get("/users/available-seats");
return await api.get<SeatsAvailable>("/users/available-seats");
});

if (result.isLoading || result.isError || !result.data) {
Expand Down
Loading

0 comments on commit bc4f4b6

Please sign in to comment.