Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

29/add loader to production list #43

Merged
merged 10 commits into from
Apr 11, 2024
4 changes: 2 additions & 2 deletions src/components/landing-page/create-production.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
} from "./form-elements.tsx";
import { API } from "../../api/api.ts";
import { useGlobalState } from "../../global-state/context-provider.tsx";
import { Loader } from "../loader/loader.tsx";
import { Spinner } from "../loader/loader.tsx";
import { isMobile } from "../../bowser.ts";

type FormValues = {
Expand Down Expand Up @@ -154,7 +154,7 @@ export const CreateProduction = () => {
onClick={handleSubmit(onSubmit)}
>
Create Production
{loading && <Loader className="create-production" />}
{loading && <Spinner className="create-production" />}
</ActionButton>
{createdProductionId !== null && (
<ProductionConfirmation>
Expand Down
31 changes: 17 additions & 14 deletions src/components/landing-page/productions-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import { useEffect, useState } from "react";
import { API } from "../../api/api.ts";
import { TProduction } from "../production-line/types.ts";
import { useGlobalState } from "../../global-state/context-provider.tsx";
import { LoaderDots } from "../loader/loader.tsx";
import { useRefreshAnimation } from "./use-refresh-animation.ts";

const ProductionListContainer = styled.div`
display: flex;
Expand Down Expand Up @@ -41,11 +43,9 @@ export const ProductionsList = () => {
let aborted = false;

if (reloadProductionList || intervalLoad) {
setIntervalLoad(false);
API.listProductions()
.then((result) => {
if (aborted) return;

setProductions(
result
// pick laste 10 items
Expand All @@ -70,6 +70,7 @@ export const ProductionsList = () => {
dispatch({
type: "PRODUCTION_LIST_FETCHED",
});
setIntervalLoad(false);
})
.catch(() => {
// TODO handle error/retry
Expand All @@ -79,7 +80,9 @@ export const ProductionsList = () => {
return () => {
aborted = true;
};
}, [dispatch, reloadProductionList, intervalLoad]);
}, [dispatch, intervalLoad, reloadProductionList]);

const showRefreshing = useRefreshAnimation({ reloadProductionList });

useEffect(() => {
const interval = window.setInterval(() => {
Expand All @@ -92,16 +95,16 @@ export const ProductionsList = () => {
}, []);

return (
<ProductionListContainer>
{/* // TODO handle so future load-component isn't shown on every update
// TODO ex className={loading && !intervalLoad ? "active" : "in-active"} */}
{/* TODO add loading indicator */}
{productions.map((p) => (
<ProductionItem key={p.id}>
<ProductionName>{p.name}</ProductionName>
<ProductionId>{p.id}</ProductionId>
</ProductionItem>
))}
</ProductionListContainer>
<>
<LoaderDots className={showRefreshing ? "active" : "in-active"} />
<ProductionListContainer>
{productions.map((p) => (
<ProductionItem key={p.id}>
<ProductionName>{p.name}</ProductionName>
<ProductionId>{p.id}</ProductionId>
</ProductionItem>
))}
</ProductionListContainer>
</>
);
};
35 changes: 35 additions & 0 deletions src/components/landing-page/use-refresh-animation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { useEffect, useState } from "react";

type TUseRefreshAnimationOptions = {
reloadProductionList: boolean;
};

export const useRefreshAnimation = ({
reloadProductionList,
}: TUseRefreshAnimationOptions) => {
const [showRefreshing, setShowRefreshing] = useState(true);

useEffect(() => {
let timeout: number | null = null;

if (showRefreshing) {
timeout = window.setTimeout(() => {
setShowRefreshing(false);
}, 1500);
}

return () => {
if (timeout !== null) {
window.clearTimeout(timeout);
}
};
}, [showRefreshing]);

useEffect(() => {
if (reloadProductionList) {
setShowRefreshing(true);
}
}, [reloadProductionList]);

return showRefreshing;
};
48 changes: 46 additions & 2 deletions src/components/loader/loader.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import styled from "@emotion/styled";
import { FC } from "react";
import { FC, useEffect, useState } from "react";

const Loading = styled.div`
border: 4px solid rgba(0, 0, 0, 0.1);
Expand Down Expand Up @@ -49,8 +49,52 @@ const Loading = styled.div`
}
`;

const Text = styled.span`
padding-left: 2rem;
font-size: 1.8rem;
&.active {
color: #cdcdcd;
}
&.in-active {
color: #242424;
}
`;

const Dots = styled.span`
padding-left: 0.2rem;
font-size: 2rem;
transform: translateY(-50%);
&.active {
color: #cdcdcd;
}
&.in-active {
color: #242424;
}
`;

type Props = { className: string };

export const Loader: FC<Props> = ({ className }: Props) => {
export const Spinner: FC<Props> = ({ className }: Props) => {
return <Loading className={className} />;
};

export const LoaderDots: FC<Props> = ({ className }: Props) => {
const [dots, setDots] = useState<string>(".");

useEffect(() => {
const intervalId = window.setInterval(() => {
setDots((prevDots) => (prevDots.length > 2 ? "." : `${prevDots}.`));
}, 300);

return () => {
clearInterval(intervalId);
};
}, []);

return (
<div>
<Text className={className}>refreshing</Text>
<Dots className={className}>{dots}</Dots>
</div>
);
};
4 changes: 2 additions & 2 deletions src/components/production-line/production-line.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { ActionButton } from "../landing-page/form-elements.tsx";
import { UserList } from "./user-list.tsx";
import { API } from "../../api/api.ts";
import { noop } from "../../helpers.ts";
import { Loader } from "../loader/loader.tsx";
import { Spinner } from "../loader/loader.tsx";

const TempDiv = styled.div`
padding: 1rem;
Expand Down Expand Up @@ -91,7 +91,7 @@ export const ProductionLine: FC = () => {
<TempDiv>
<ActionButton onClick={exit}>Exit</ActionButton>
</TempDiv>
{loading && <Loader className="join-production" />}
{loading && <Spinner className="join-production" />}
{!loading && (
<>
<TempDiv>Production View</TempDiv>
Expand Down
Loading