Added teams pages. Refactored hooks.

This commit is contained in:
Mike Cao 2024-01-28 18:33:40 -08:00
parent a2c202fa36
commit 9448aa3ab5
136 changed files with 387 additions and 287 deletions

View file

@ -0,0 +1,20 @@
import * as reactQuery from '@tanstack/react-query';
import { useApi as nextUseApi } from 'next-basics';
import { getClientAuthToken } from 'lib/client';
import { SHARE_TOKEN_HEADER } from 'lib/constants';
import useStore from 'store/app';
const selector = (state: { shareToken: { token?: string } }) => state.shareToken;
export function useApi() {
const shareToken = useStore(selector);
const { get, post, put, del } = nextUseApi(
{ authorization: `Bearer ${getClientAuthToken()}`, [SHARE_TOKEN_HEADER]: shareToken?.token },
process.env.basePath,
);
return { get, post, put, del, ...reactQuery };
}
export default useApi;

View file

@ -0,0 +1,28 @@
import { useEffect } from 'react';
import useStore, { setConfig } from 'store/app';
import { useApi } from './useApi';
let loading = false;
export function useConfig() {
const { config } = useStore();
const { get } = useApi();
const configUrl = process.env.configUrl;
async function loadConfig() {
const data = await get(configUrl);
loading = false;
setConfig(data);
}
useEffect(() => {
if (!config && !loading && configUrl) {
loading = true;
loadConfig();
}
}, []);
return config;
}
export default useConfig;

View file

@ -0,0 +1,38 @@
import { UseQueryOptions } from '@tanstack/react-query';
import { useState, Dispatch, SetStateAction } from 'react';
import { useApi } from './useApi';
import { FilterResult, SearchFilter } from 'lib/types';
export interface FilterQueryResult<T> {
result: FilterResult<T>;
query: any;
params: SearchFilter;
setParams: Dispatch<SetStateAction<T | SearchFilter>>;
}
export function useFilterQuery<T>({
queryKey,
queryFn,
...options
}: UseQueryOptions): FilterQueryResult<T> {
const [params, setParams] = useState<T | SearchFilter>({
query: '',
page: 1,
});
const { useQuery } = useApi();
const { data, ...query } = useQuery({
queryKey: [{ ...queryKey, ...params }],
queryFn: () => queryFn(params as any),
...options,
});
return {
result: data as FilterResult<any>,
query,
params,
setParams,
};
}
export default useFilterQuery;

View file

@ -0,0 +1,22 @@
import useApi from './useApi';
import useUser from './useUser';
export function useLogin() {
const { get, useQuery } = useApi();
const { user, setUser } = useUser();
const query = useQuery({
queryKey: ['login'],
queryFn: async () => {
const data = await get('/auth/verify');
setUser(data);
return data;
},
});
return { user, ...query };
}
export default useLogin;

View file

@ -0,0 +1,88 @@
import { produce } from 'immer';
import { useCallback, useEffect, useState } from 'react';
import { useApi } from './useApi';
import { useTimezone } from '../useTimezone';
import { useMessages } from '../useMessages';
export function useReport(reportId: string, defaultParameters: { [key: string]: any }) {
const [report, setReport] = useState(null);
const [isRunning, setIsRunning] = useState(false);
const { get, post } = useApi();
const [timezone] = useTimezone();
const { formatMessage, labels } = useMessages();
const baseParameters = {
name: formatMessage(labels.untitled),
description: '',
parameters: {},
};
const loadReport = async (id: string) => {
const data: any = await get(`/reports/${id}`);
const { dateRange } = data?.parameters || {};
const { startDate, endDate } = dateRange || {};
if (startDate && endDate) {
dateRange.startDate = new Date(startDate);
dateRange.endDate = new Date(endDate);
}
setReport(data);
};
const runReport = useCallback(
async (parameters: { [key: string]: any }) => {
setIsRunning(true);
const { type } = report;
const data = await post(`/reports/${type}`, { ...parameters, timezone });
setReport(
produce((state: any) => {
state.parameters = parameters;
state.data = data;
return state;
}),
);
setIsRunning(false);
},
[report, timezone],
);
const updateReport = useCallback(
async (data: { [x: string]: any; parameters: any }) => {
setReport(
produce((state: any) => {
const { parameters, ...rest } = data;
if (parameters) {
state.parameters = { ...state.parameters, ...parameters };
}
for (const key in rest) {
state[key] = rest[key];
}
return state;
}),
);
},
[report],
);
useEffect(() => {
if (!reportId) {
setReport({ ...baseParameters, ...defaultParameters });
} else {
loadReport(reportId);
}
}, []);
return { report, runReport, updateReport, isRunning };
}
export default useReport;

View file

@ -0,0 +1,30 @@
import { useState } from 'react';
import useApi from './useApi';
import useFilterQuery from './useFilterQuery';
export function useReports(websiteId?: string) {
const [modified, setModified] = useState(Date.now());
const { get, del, useMutation } = useApi();
const { mutate } = useMutation({ mutationFn: (reportId: string) => del(`/reports/${reportId}`) });
const queryResult = useFilterQuery({
queryKey: ['reports', { websiteId, modified }],
queryFn: (params: any) => {
return get(websiteId ? `/websites/${websiteId}/reports` : `/reports`, params);
},
});
const deleteReport = (id: any) => {
mutate(id, {
onSuccess: () => {
setModified(Date.now());
},
});
};
return {
...queryResult,
deleteReport,
};
}
export default useReports;

View file

@ -0,0 +1,27 @@
import useStore, { setShareToken } from 'store/app';
import useApi from './useApi';
const selector = (state: { shareToken: string }) => state.shareToken;
export function useShareToken(shareId: string): {
shareToken: any;
isLoading?: boolean;
error?: Error;
} {
const shareToken = useStore(selector);
const { get, useQuery } = useApi();
const { isLoading, error } = useQuery({
queryKey: ['share', shareId],
queryFn: async () => {
const data = await get(`/share/${shareId}`);
setShareToken(data);
return data;
},
});
return { shareToken, isLoading, error };
}
export default useShareToken;

View file

@ -0,0 +1,12 @@
import useApi from './useApi';
export function useTeam(teamId: string) {
const { get, useQuery } = useApi();
return useQuery({
queryKey: ['teams', teamId],
queryFn: () => get(`/teams/${teamId}`),
enabled: !!teamId,
});
}
export default useTeam;

View file

@ -0,0 +1,15 @@
import useApi from './useApi';
import useFilterQuery from './useFilterQuery';
export function useTeamWebsites(teamId: string) {
const { get } = useApi();
return useFilterQuery({
queryKey: ['teams:websites', { teamId }],
queryFn: (params: any) => {
return get(`/teams/${teamId}/websites`, params);
},
});
}
export default useTeamWebsites;

View file

@ -0,0 +1,11 @@
import useStore, { setUser } from 'store/app';
const selector = (state: { user: any }) => state.user;
export function useUser() {
const user = useStore(selector);
return { user, setUser };
}
export default useUser;

View file

@ -0,0 +1,12 @@
import useApi from './useApi';
export function useWebsite(websiteId: string) {
const { get, useQuery } = useApi();
return useQuery({
queryKey: ['websites', websiteId],
queryFn: () => get(`/websites/${websiteId}`),
enabled: !!websiteId,
});
}
export default useWebsite;

View file

@ -0,0 +1,20 @@
import useApi from './useApi';
import useFilterQuery from './useFilterQuery';
import useCache from 'store/cache';
export function useWebsites({ userId, teamId }: { userId?: string; teamId?: string }) {
const { get } = useApi();
const modified = useCache((state: any) => state?.websites);
return useFilterQuery({
queryKey: ['websites', { userId, teamId, modified }],
queryFn: (params: any) => {
return get(teamId ? `/teams/${teamId}/websites` : '/websites', {
...params,
});
},
enabled: !!(userId || teamId),
});
}
export default useWebsites;