Skip to content

Commit

Permalink
small improvements all over the app
Browse files Browse the repository at this point in the history
  • Loading branch information
cstenglein committed Jan 14, 2024
1 parent 3fbb574 commit 1facba4
Show file tree
Hide file tree
Showing 19 changed files with 180 additions and 172 deletions.
2 changes: 1 addition & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Route, Routes, useLocation, useNavigate } from "react-router-dom";
import "react-toastify/dist/ReactToastify.css";
import "./App.css";
import Layout from "./layouts/Layout";
import LoadingScreen from "./components/LoadingScreen";
import LoadingScreen from "./layouts/LoadingScreen";
import RequireAuth from "./components/RequireAuth";
import RequireSetup from "./components/RequireSetup";
import SkeletonLoadingScreen from "./layouts/SkeletonLoadingScreen";
Expand Down
3 changes: 2 additions & 1 deletion src/ErrorBoundary.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { TFunction } from "i18next";
import { Component, ErrorInfo, ReactNode } from "react";
import { withTranslation } from "react-i18next";

interface Props {
t: any;
t: TFunction<[string, string], undefined>;
children: ReactNode;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ type Props = {
app: AppStatus;
};

export const AppStatusCard: FC<Props> = ({ app }) => {
export const AppStatusItem: FC<Props> = ({ app }) => {
const { id } = app;
const appName = availableApps.get(id)?.name;

Expand All @@ -27,4 +27,4 @@ export const AppStatusCard: FC<Props> = ({ app }) => {
);
};

export default AppStatusCard;
export default AppStatusItem;
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AppStatus } from "@/models/app-status";
import AppStatusCard from "@/pages/Home/AppStatusCard";
import AppStatusItem from "../AppStatusItem";
import { render, screen } from "test-utils";

const testApp: AppStatus = {
Expand All @@ -11,9 +11,9 @@ const testApp: AppStatus = {
error: "",
};

describe("AppStatusCard", () => {
describe("AppStatusItem", () => {
it("should link to 'address'", () => {
render(<AppStatusCard app={testApp} />);
render(<AppStatusItem app={testApp} />);

const appCard = screen.getAllByRole("link");
expect(appCard[0].getAttribute("href")).toEqual("http://127.0.0.1");
Expand All @@ -28,7 +28,7 @@ describe("AppStatusCard", () => {
},
writable: true,
});
render(<AppStatusCard app={testApp} />);
render(<AppStatusItem app={testApp} />);

const appCard = screen.getAllByRole("link");
expect(appCard[0].getAttribute("href")).toEqual(
Expand Down
1 change: 1 addition & 0 deletions src/hooks/use-sse.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { availableApps } from "@/utils/availableApps";
/**
* Establishes a SSE connection if not available yet & attaches / removes event listeners
* to the single events to update the SSEContext
* Only use once per page, otherwise you will have multiple connections; use useContext(SSEContext) instead
* @returns the infos from the SSEContext
*/
function useSSE() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,19 @@
import { FC, useContext } from "react";
import LoadingSpinner from "./LoadingSpinner/LoadingSpinner";
import LoadingSpinner from "../components/LoadingSpinner/LoadingSpinner";
import { AppContext } from "@/context/app-context";
import RaspiBlitzLogo from "@/assets/RaspiBlitz_Logo_Main.svg?react";
import RaspiBlitzLogoDark from "@/assets/RaspiBlitz_Logo_Main_Negative.svg?react";

// Loading Screen for the initial loading of the app
const LoadingScreen: FC = () => {
const appCtx = useContext(AppContext);

return (
<div className="flex h-screen w-screen flex-col items-center justify-center bg-gray-100 dark:bg-gray-700">
<main className="flex h-screen w-screen flex-col items-center justify-center bg-gray-100 dark:bg-gray-700">
{!appCtx.darkMode && <RaspiBlitzLogo className="mb-5 h-12" />}
{appCtx.darkMode && <RaspiBlitzLogoDark className="mb-5 h-12" />}
<LoadingSpinner color="text-yellow-500" />
</div>
</main>
);
};

Expand Down
17 changes: 17 additions & 0 deletions src/layouts/PageLoadingScreen.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { FC } from "react";
import LoadingSpinner from "../components/LoadingSpinner/LoadingSpinner";

// Loading Screen where sidebar is visible and usable
const PageLoadingScreen: FC = () => {
return (
<main
className={`content-container page-container bg-gray-100 p-5 transition-colors dark:bg-gray-700 dark:text-white lg:pb-8 lg:pr-8 lg:pt-8`}
>
<section className="content-container flex items-center justify-center">
<LoadingSpinner color="text-yellow-500" />
</section>
</main>
);
};

export default PageLoadingScreen;
8 changes: 4 additions & 4 deletions src/layouts/SideDrawer.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import {
ArrowRightOnRectangleIcon,
ArrowRightStartOnRectangleIcon,
Cog6ToothIcon,
HomeIcon,
Squares2X2Icon,
} from "@heroicons/react/24/outline";
import { SSEContext } from "@/context/sse-context";
import AppStatusCard from "@/pages/Home/AppStatusCard";
import AppStatusItem from "@/components/AppStatusItem";
import type { FC } from "react";
import { useContext } from "react";
import { useTranslation } from "react-i18next";
Expand Down Expand Up @@ -48,7 +48,7 @@ export const SideDrawer: FC = () => {
{appStatus
.filter((app) => app.installed)
.map((app) => (
<AppStatusCard app={app} key={app.id} />
<AppStatusItem app={app} key={app.id} />
))}
</div>

Expand All @@ -57,7 +57,7 @@ export const SideDrawer: FC = () => {
onClick={logout}
className="bd-button mb-3 flex h-8 w-60 items-center justify-center"
>
<ArrowRightOnRectangleIcon className="mr-1 inline-block h-5 w-5" />
<ArrowRightStartOnRectangleIcon className="mr-1 inline-block h-5 w-5" />
{t("navigation.logout")}
</button>
</div>
Expand Down
1 change: 1 addition & 0 deletions src/layouts/SkeletonLoadingScreen.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { FC } from "react";
import LoadingSpinner from "@/components/LoadingSpinner/LoadingSpinner";

// Loading Screen wher sidebar is visible but not usable
const SkeletonLoadingScreen: FC = () => {
return (
<>
Expand Down
4 changes: 2 additions & 2 deletions src/pages/Apps/AppCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export const AppCard: FC<Props> = ({
};

return (
<div className="bd-card transition-colors dark:bg-gray-800">
<article className="bd-card transition-colors dark:bg-gray-800">
<div className="relative mt-2 flex h-4/6 w-full flex-row items-center">
{installed && (
<>
Expand Down Expand Up @@ -145,7 +145,7 @@ export const AppCard: FC<Props> = ({
&nbsp;{t("apps.info")}
</button>
</div>
</div>
</article>
);
};

Expand Down
6 changes: 3 additions & 3 deletions src/pages/Apps/AppCardAlby.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { PlusIcon, LinkIcon } from "@heroicons/react/24/outline";
import { FC } from "react";
import type { FC } from "react";
import { useTranslation } from "react-i18next";
import AppIcon from "@/components/AppIcon";
import { toast } from "react-toastify";
Expand Down Expand Up @@ -57,7 +57,7 @@ export const AppCardAlby: FC = () => {
};

return (
<div className="bd-card transition-colors dark:bg-gray-800">
<article className="bd-card transition-colors dark:bg-gray-800">
<div className="relative mt-2 flex h-4/6 w-full flex-row items-center">
{/* Icon */}
<div className="mt-4 flex w-1/4 items-center justify-center p-2">
Expand Down Expand Up @@ -94,7 +94,7 @@ export const AppCardAlby: FC = () => {
</a>
)}
</div>
</div>
</article>
);
};

Expand Down
18 changes: 7 additions & 11 deletions src/pages/Apps/AppInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import AppIcon from "@/components/AppIcon";
import ButtonWithSpinner from "@/components/ButtonWithSpinner/ButtonWithSpinner";
import PageLoadingScreen from "@/layouts/PageLoadingScreen";
import { AppStatus } from "@/models/app-status";
import { App } from "@/models/app.model";
import { availableApps } from "@/utils/availableApps";
import {
ChevronLeftIcon,
PlusIcon,
TrashIcon,
} from "@heroicons/react/24/outline";
import { AppStatus } from "@/models/app-status";
import { FC, useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import AppIcon from "@/components/AppIcon";
import ButtonWithSpinner from "@/components/ButtonWithSpinner/ButtonWithSpinner";
import LoadingSpinner from "@/components/LoadingSpinner/LoadingSpinner";
import { App } from "@/models/app.model";
import { availableApps } from "@/utils/availableApps";
import ImageCarousel from "./ImageCarousel";

export type Props = {
Expand Down Expand Up @@ -70,11 +70,7 @@ export const AppInfo: FC<Props> = ({
}, [id]);

if (isLoading) {
return (
<main className="page-container content-container flex w-full items-center justify-center bg-gray-100 dark:bg-gray-700 dark:text-white">
<LoadingSpinner />
</main>
);
return <PageLoadingScreen />;
}

return (
Expand Down
40 changes: 40 additions & 0 deletions src/pages/Apps/AppList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { AppStatus } from "@/models/app-status";
import { availableApps } from "@/utils/availableApps";
import { t } from "i18next";
import { FC } from "react";
import AppCard from "./AppCard";
import { App } from "@/models/app.model";

type Props = {
title: string;
apps: AppStatus[];
onInstall: (id: string) => void;
onOpenDetails: (app: App) => void;
};

const AppList: FC<Props> = ({ title, apps, onInstall, onOpenDetails }) => {
return (
<section className="flex h-full flex-wrap">
<h2 className="w-full pb-5 pt-8 text-xl font-bold dark:text-gray-200">
{title}
</h2>
<div className="grid w-full grid-cols-1 gap-5 lg:grid-cols-3 lg:gap-8">
{apps.map((appStatus: AppStatus) => {
return (
<AppCard
key={appStatus.id}
appInfo={availableApps.get(appStatus.id)!}
appStatusInfo={appStatus}
installed={appStatus.installed}
installingApp={null}
onInstall={onInstall}
onOpenDetails={onOpenDetails}
/>
);
})}
</div>
</section>
);
};

export default AppList;
93 changes: 29 additions & 64 deletions src/pages/Apps/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import type { FC } from "react";
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { toast } from "react-toastify";
import LoadingSpinner from "@/components/LoadingSpinner/LoadingSpinner";
import useSSE from "@/hooks/use-sse";
import PageLoadingScreen from "@/layouts/PageLoadingScreen";
import { AppStatus } from "@/models/app-status";
import { App } from "@/models/app.model";
import { enableGutter } from "@/utils";
import { availableApps } from "@/utils/availableApps";
import { checkError } from "@/utils/checkError";
import { instance } from "@/utils/interceptor";
import AppCard from "./AppCard";
import type { FC } from "react";
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { toast } from "react-toastify";
import AppCardAlby from "./AppCardAlby";
import AppInfo from "./AppInfo";
import AppList from "./AppList";

export const Apps: FC = () => {
const { t } = useTranslation(["translation", "apps"]);
Expand All @@ -34,9 +33,6 @@ export const Apps: FC = () => {
return !app.installed;
});

// in case no App data received yet => show loading
const isLoading = appStatus.length === 0;

const installHandler = (id: string) => {
instance.post(`apps/install/${id}`).catch((err) => {
toast.error(checkError(err));
Expand Down Expand Up @@ -73,63 +69,32 @@ export const Apps: FC = () => {
);
}

// in case no App data received yet => show loading screen
if (appStatus.length === 0) {
return <PageLoadingScreen />;
}

return (
<main className="content-container page-container bg-gray-100 p-5 transition-colors dark:bg-gray-700 dark:text-white lg:pb-8 lg:pr-8 lg:pt-8">
{isLoading && (
<section className="content-container flex items-center justify-center">
<LoadingSpinner color="text-yellow-500" />
<>
<AppList
apps={installedApps}
title={t("apps.installed")}
onInstall={installHandler}
onOpenDetails={openDetailsHandler}
/>
<AppList
apps={notInstalledApps}
title={t("apps.available")}
onInstall={installHandler}
onOpenDetails={openDetailsHandler}
/>
<section className="flex h-full flex-wrap pt-8">
<div className="grid w-full grid-cols-1 gap-5 lg:grid-cols-3 lg:gap-8">
<AppCardAlby />
</div>
</section>
)}
{!isLoading && (
<>
<section className="flex h-full flex-wrap">
<h2 className="w-full pb-5 pt-8 text-xl font-bold dark:text-gray-200">
{t("apps.installed")}
</h2>
<div className="grid w-full grid-cols-1 gap-5 lg:grid-cols-3 lg:gap-8">
{installedApps.map((appStatus: AppStatus) => {
return (
<article key={appStatus.id}>
<AppCard
appInfo={availableApps.get(appStatus.id)!}
appStatusInfo={appStatus}
installed={true}
installingApp={null}
onInstall={() => installHandler(appStatus.id)}
onOpenDetails={openDetailsHandler}
/>
</article>
);
})}
</div>
</section>
<section className="flex h-full flex-wrap">
<h2 className="block w-full pb-5 pt-8 text-xl font-bold dark:text-gray-200">
{t("apps.available")}
</h2>
<div className="grid w-full grid-cols-1 gap-5 lg:grid-cols-3 lg:gap-8">
{notInstalledApps.map((appStatus: AppStatus) => {
return (
<article key={appStatus.id}>
<AppCard
appInfo={availableApps.get(appStatus.id)!}
appStatusInfo={appStatus}
installed={false}
installingApp={installingApp}
onInstall={() => installHandler(appStatus.id)}
onOpenDetails={openDetailsHandler}
/>
</article>
);
})}

<article>
<AppCardAlby />
</article>
</div>
</section>
</>
)}
</>
</main>
);
};
Expand Down
Loading

0 comments on commit 1facba4

Please sign in to comment.