dev: hello world

This commit is contained in:
vamsi 2022-11-19 19:51:26 +05:30
commit 6037fed3f4
145 changed files with 16848 additions and 0 deletions

View file

@ -0,0 +1,15 @@
import { UserProvider } from "./user.context";
import { ToastContextProvider } from "./toast.context";
import { ThemeContextProvider } from "./theme.context";
const GlobalContextProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
return (
<UserProvider>
<ToastContextProvider>
<ThemeContextProvider>{children}</ThemeContextProvider>
</ToastContextProvider>
</UserProvider>
);
};
export default GlobalContextProvider;

144
contexts/theme.context.tsx Normal file
View file

@ -0,0 +1,144 @@
import React, { createContext, useCallback, useReducer, useEffect } from "react";
// constants
import {
TOGGLE_SIDEBAR,
REHYDRATE_THEME,
SET_ISSUE_VIEW,
SET_GROUP_BY_PROPERTY,
} from "constants/theme.context.constants";
// components
import ToastAlert from "components/toast-alert";
export const themeContext = createContext<ContextType>({} as ContextType);
// types
import type { IIssue, NestedKeyOf } from "types";
type Theme = {
collapsed: boolean;
issueView: "list" | "kanban" | null;
groupByProperty: NestedKeyOf<IIssue> | null;
};
type ReducerActionType = {
type:
| typeof TOGGLE_SIDEBAR
| typeof REHYDRATE_THEME
| typeof SET_ISSUE_VIEW
| typeof SET_GROUP_BY_PROPERTY;
payload?: Partial<Theme>;
};
type ContextType = {
collapsed: boolean;
issueView: "list" | "kanban" | null;
groupByProperty: NestedKeyOf<IIssue> | null;
toggleCollapsed: () => void;
setIssueView: (display: "list" | "kanban") => void;
setGroupByProperty: (property: NestedKeyOf<IIssue> | null) => void;
};
type StateType = Theme;
type ReducerFunctionType = (state: StateType, action: ReducerActionType) => StateType;
export const initialState: StateType = {
collapsed: false,
issueView: null,
groupByProperty: null,
};
export const reducer: ReducerFunctionType = (state, action) => {
const { type, payload } = action;
switch (type) {
case TOGGLE_SIDEBAR:
const newState = {
...state,
collapsed: !state.collapsed,
};
localStorage.setItem("theme", JSON.stringify(newState));
return newState;
case REHYDRATE_THEME: {
let newState: any = localStorage.getItem("theme");
if (newState !== null) {
newState = JSON.parse(newState);
}
return { ...initialState, ...newState };
}
case SET_ISSUE_VIEW: {
const newState = {
...state,
issueView: payload?.issueView || "list",
};
localStorage.setItem("theme", JSON.stringify(newState));
return {
...state,
...newState,
};
}
case SET_GROUP_BY_PROPERTY: {
const newState = {
...state,
groupByProperty: payload?.groupByProperty || null,
};
localStorage.setItem("theme", JSON.stringify(newState));
return {
...state,
...newState,
};
}
default: {
return state;
}
}
};
export const ThemeContextProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [state, dispatch] = useReducer(reducer, initialState);
const toggleCollapsed = useCallback(() => {
dispatch({
type: TOGGLE_SIDEBAR,
});
}, []);
const setIssueView = useCallback((display: "list" | "kanban") => {
dispatch({
type: SET_ISSUE_VIEW,
payload: {
issueView: display,
},
});
}, []);
const setGroupByProperty = useCallback((property: NestedKeyOf<IIssue> | null) => {
dispatch({
type: SET_GROUP_BY_PROPERTY,
payload: {
groupByProperty: property,
},
});
}, []);
useEffect(() => {
dispatch({
type: REHYDRATE_THEME,
});
}, []);
return (
<themeContext.Provider
value={{
collapsed: state.collapsed,
toggleCollapsed,
issueView: state.issueView,
setIssueView,
groupByProperty: state.groupByProperty,
setGroupByProperty,
}}
>
<ToastAlert />
{children}
</themeContext.Provider>
);
};

101
contexts/toast.context.tsx Normal file
View file

@ -0,0 +1,101 @@
import React, { createContext, useCallback, useReducer } from "react";
// uuid
import { v4 as uuid } from "uuid";
// constants
import { SET_TOAST_ALERT, REMOVE_TOAST_ALERT } from "constants/toast.context.constants";
// components
import ToastAlert from "components/toast-alert";
export const toastContext = createContext<ContextType>({} as ContextType);
// types
type ToastAlert = {
id: string;
title: string;
message?: string;
type: "success" | "error" | "warning" | "info";
};
type ReducerActionType = {
type: typeof SET_TOAST_ALERT | typeof REMOVE_TOAST_ALERT;
payload: ToastAlert;
};
type ContextType = {
alerts?: ToastAlert[];
removeAlert: (id: string) => void;
setToastAlert: (data: {
title: string;
type?: "success" | "error" | "warning" | "info" | undefined;
message?: string | undefined;
}) => void;
};
type StateType = {
toastAlerts?: ToastAlert[];
};
type ReducerFunctionType = (state: StateType, action: ReducerActionType) => StateType;
export const initialState: StateType = {
toastAlerts: [],
};
export const reducer: ReducerFunctionType = (state, action) => {
const { type, payload } = action;
switch (type) {
case SET_TOAST_ALERT:
return {
...state,
toastAlerts: [...(state.toastAlerts ?? []), payload],
};
case REMOVE_TOAST_ALERT:
return {
...state,
toastAlerts: state.toastAlerts?.filter((toastAlert) => toastAlert.id !== payload.id),
};
default: {
return state;
}
}
};
export const ToastContextProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
const [state, dispatch] = useReducer(reducer, initialState);
const removeAlert = useCallback((id: string) => {
dispatch({
type: REMOVE_TOAST_ALERT,
payload: { id, title: "", message: "", type: "success" },
});
}, []);
const setToastAlert = useCallback(
(data: {
title: string;
type?: "success" | "error" | "warning" | "info";
message?: string;
}) => {
const id = uuid();
const { title, type, message } = data;
dispatch({
type: SET_TOAST_ALERT,
payload: { id, title, message, type: type ?? "success" },
});
const timer = setTimeout(() => {
removeAlert(id);
clearTimeout(timer);
}, 5000);
},
[removeAlert]
);
return (
<toastContext.Provider value={{ setToastAlert, removeAlert, alerts: state.toastAlerts }}>
<ToastAlert />
{children}
</toastContext.Provider>
);
};

154
contexts/user.context.tsx Normal file
View file

@ -0,0 +1,154 @@
import React, { createContext, ReactElement, useEffect, useState, useCallback } from "react";
// next
import Router from "next/router";
import { useRouter } from "next/router";
// swr
import useSWR from "swr";
// services
import userService from "lib/services/user.service";
import issuesServices from "lib/services/issues.services";
import stateServices from "lib/services/state.services";
import sprintsServices from "lib/services/cycles.services";
import projectServices from "lib/services/project.service";
import workspaceService from "lib/services/workspace.service";
// constants
import {
CURRENT_USER,
PROJECTS_LIST,
USER_WORKSPACES,
USER_WORKSPACE_INVITATIONS,
PROJECT_ISSUES_LIST,
STATE_LIST,
CYCLE_LIST,
} from "constants/fetch-keys";
// types
import type { KeyedMutator } from "swr";
import type { IUser, IWorkspace, IProject, IIssue, IssueResponse, ICycle, IState } from "types";
interface IUserContextProps {
user?: IUser;
isUserLoading: boolean;
mutateUser: KeyedMutator<IUser>;
activeWorkspace?: IWorkspace;
mutateWorkspaces: KeyedMutator<IWorkspace[]>;
workspaces?: IWorkspace[];
projects?: IProject[];
setActiveProject: React.Dispatch<React.SetStateAction<IProject | undefined>>;
mutateProjects: KeyedMutator<IProject[]>;
activeProject?: IProject;
issues?: IssueResponse;
mutateIssues: KeyedMutator<IssueResponse>;
sprints?: ICycle[];
mutateSprints: KeyedMutator<ICycle[]>;
states?: IState[];
mutateStates: KeyedMutator<IState[]>;
}
export const UserContext = createContext<IUserContextProps>({} as IUserContextProps);
export const UserProvider = ({ children }: { children: ReactElement }) => {
const router = useRouter();
const { projectId } = router.query;
const [activeWorkspace, setActiveWorkspace] = useState<IWorkspace | undefined>();
const [activeProject, setActiveProject] = useState<IProject | undefined>();
// API to fetch user information
const { data, error, mutate } = useSWR<IUser>(CURRENT_USER, () => userService.currentUser(), {
shouldRetryOnError: false,
});
const {
data: workspaces,
error: workspaceError,
mutate: mutateWorkspaces,
} = useSWR<IWorkspace[]>(
data ? USER_WORKSPACES : null,
data ? () => workspaceService.userWorkspaces() : null,
{
shouldRetryOnError: false,
}
);
const { data: projects, mutate: mutateProjects } = useSWR<IProject[]>(
activeWorkspace ? PROJECTS_LIST(activeWorkspace.slug) : null,
activeWorkspace ? () => projectServices.getProjects(activeWorkspace.slug) : null
);
const { data: issues, mutate: mutateIssues } = useSWR<IssueResponse>(
activeWorkspace && activeProject
? PROJECT_ISSUES_LIST(activeWorkspace.slug, activeProject.id)
: null,
activeWorkspace && activeProject
? () => issuesServices.getIssues(activeWorkspace.slug, activeProject.id)
: null
);
const { data: states, mutate: mutateStates } = useSWR<IState[]>(
activeWorkspace && activeProject ? STATE_LIST(activeProject.id) : null,
activeWorkspace && activeProject
? () => stateServices.getStates(activeWorkspace.slug, activeProject.id)
: null
);
const { data: sprints, mutate: mutateSprints } = useSWR<ICycle[]>(
activeWorkspace && activeProject ? CYCLE_LIST(activeProject.id) : null,
activeWorkspace && activeProject
? () => sprintsServices.getCycles(activeWorkspace.slug, activeProject.id)
: null
);
useEffect(() => {
if (!projects) return;
const activeProject = projects.find((project) => project.id === projectId);
setActiveProject(activeProject ?? projects[0]);
}, [projectId, projects]);
useEffect(() => {
if (data?.last_workspace_id) {
const workspace = workspaces?.find((item) => item.id === data?.last_workspace_id);
if (workspace) {
setActiveWorkspace(workspace);
} else {
const workspace = workspaces?.[0];
setActiveWorkspace(workspace);
userService.updateUser({ last_workspace_id: workspace?.id });
}
} else if (data) {
const workspace = workspaces?.[0];
setActiveWorkspace(workspace);
userService.updateUser({ last_workspace_id: workspace?.id });
}
}, [data, workspaces]);
useEffect(() => {
if (!workspaces) return;
if (workspaces.length === 0) Router.push("/invitations");
}, [workspaces]);
return (
<UserContext.Provider
value={{
user: error ? undefined : data,
isUserLoading: !(!!data || !!error),
mutateUser: mutate,
activeWorkspace: workspaceError ? undefined : activeWorkspace,
mutateWorkspaces: mutateWorkspaces,
workspaces: workspaceError ? undefined : workspaces,
projects,
mutateProjects: mutateProjects,
activeProject,
issues,
mutateIssues,
sprints,
mutateSprints,
states,
mutateStates,
setActiveProject,
}}
>
{children}
</UserContext.Provider>
);
};