Skip to content

Commit

Permalink
✨ feat (App Frontend): View Changelog and Version info in the app (#167)
Browse files Browse the repository at this point in the history
* ✨ feat (App Frontend): View Changelog and Version info in the app
branch: main

* 🧼 format & lint (App Frontend):
branch: view-version
  • Loading branch information
Strehk authored May 16, 2024
1 parent 051cda4 commit 8ca82db
Show file tree
Hide file tree
Showing 13 changed files with 367 additions and 22 deletions.
10 changes: 4 additions & 6 deletions .github/workflows/build_publish_container_images.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ jobs:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}


- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
Expand All @@ -32,8 +31,9 @@ jobs:
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: FONTAWESOME_NPM_AUTH_TOKEN=${{ secrets.FONTAWESOME_NPM_AUTH_TOKEN }}

build-args: |
FONTAWESOME_NPM_AUTH_TOKEN=${{ secrets.FONTAWESOME_NPM_AUTH_TOKEN }}
NEXT_PUBLIC_VERSION=${{ github.event.release.tag_name }}
chase-backend:
runs-on: ubuntu-latest
Expand All @@ -53,7 +53,6 @@ jobs:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}


- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
Expand Down Expand Up @@ -81,12 +80,11 @@ jobs:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}


- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: .
file: ./Dockerfile.chase.backend.db-migration
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
labels: ${{ steps.meta.outputs.labels }}
2 changes: 2 additions & 0 deletions Dockerfile.chase.frontend
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,10 @@ COPY --from=nextjs /app/staging/node_modules ./node_modules/
COPY --from=builder /app/staging/chase/frontend/public ./public/
COPY --from=builder /app/staging/chase/frontend/.next/standalone ./
COPY --from=builder /app/staging/chase/frontend/.next/static ./.next/static
ARG NEXT_PUBLIC_VERSION
ENV NODE_ENV=production
ENV PORT=3000
ENV NEXT_PUBLIC_VERSION=${NEXT_PUBLIC_VERSION}
# run the app
USER bun
EXPOSE 3000/tcp
Expand Down
Binary file modified bun.lockb
Binary file not shown.
3 changes: 2 additions & 1 deletion chase/frontend/.env.development
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
NEXT_PUBLIC_BACKEND_URL=http://localhost:3001
NEXT_PUBLIC_BACKEND_URL=http://localhost:3001
NEXT_PUBLIC_VERSION=1.1.10
21 changes: 19 additions & 2 deletions chase/frontend/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
"use client";
import React from "react";
import React, { useState } from "react";
import { useI18nContext } from "@/i18n/i18n-react";
import Navbar from "@/components/home/navbar";
import LandingHero from "@/components/home/landing_hero";
import CardSection from "@/components/home/card_section";
import TextSection from "@/components/home/text_section";
import { faCodeBranch, faExternalLink } from "@fortawesome/pro-solid-svg-icons";
import {
faCodeBranch,
faCodeCommit,
faExternalLink,
faStars,
} from "@fortawesome/pro-solid-svg-icons";
import Footer from "@/components/home/footer";
import { useMediaQuery } from "react-responsive";
import Image from "next/image";
import VersionModal from "@/components/version_modal";

export default function Home() {
const { LL } = useI18nContext();

const [versionModalVisible, setVersionModalVisible] = useState(false);

const _isDesktopOrLaptop = useMediaQuery({
query: "(min-width: 1024px)",
});
Expand Down Expand Up @@ -48,6 +56,11 @@ export default function Home() {
<TextSection
title={LL.home.ABOUT_TITEL()}
text={LL.home.ABOUT_TEXT()}
button={{
lable: LL.home.VERSION_BUTTON(),
onClick: () => setVersionModalVisible(true),
faIcon: faStars,
}}
/>
<TextSection
title={LL.home.MISSION_TITLE()}
Expand All @@ -71,6 +84,10 @@ export default function Home() {
</div>
</div>
<Footer />
<VersionModal
visible={versionModalVisible}
setVisible={setVersionModalVisible}
/>
</>
);
}
14 changes: 11 additions & 3 deletions chase/frontend/components/home/text_section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ type TextSectionProps = {
text: string;
button?: {
lable: string;
link: string;
link?: string;
onClick?: () => void;
faIcon?: IconDefinition;
};
};
Expand All @@ -30,8 +31,15 @@ export default function TextSection({ title, text, button }: TextSectionProps) {
<Button
label={button.lable}
onClick={() => {
//TODO this is not ideal, we should use actual anchor tags for this
Router.push(button.link);
if (button.onClick) {
button.onClick();
return;
}
if (button.link) {
Router.push(button.link);
return;
}
throw new Error("No link or onClick function provided");
}}
faIcon={button.faIcon}
className="mt-4"
Expand Down
18 changes: 17 additions & 1 deletion chase/frontend/components/navbar/external_links.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,19 @@ import type { IconProp } from "@fortawesome/fontawesome-svg-core";
import {
faCommentExclamation,
faNewspaper,
faStars,
} from "@fortawesome/pro-solid-svg-icons";
import { useContext } from "react";
import { useContext, useState } from "react";
import NavButton from "./button";
import VersionModal from "../version_modal";

export default function ExternalLinks() {
const { backend } = useBackend();
const conferenceId = useContext(ConferenceIdContext);
const { LL } = useI18nContext();

const [versionModalVisible, setVersionModalVisible] = useState(false);

const [conferenceData] = useBackendCall(() => {
//TODO
// biome-ignore lint/style/noNonNullAssertion:
Expand All @@ -39,6 +43,18 @@ export default function ExternalLinks() {
title={LL.navbar.BUG_REPORT()}
/>
)}
<NavButton
icon={faStars as IconProp}
onClick={() => {
setVersionModalVisible(true);
}}
title={LL.home.VERSION_BUTTON()}
/>
<VersionModal
visible={versionModalVisible}
setVisible={setVersionModalVisible}
autoOpen
/>
</>
);
}
168 changes: 168 additions & 0 deletions chase/frontend/components/version_modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
import React, { useState, useEffect, use } from "react";
import { useI18nContext } from "@/i18n/i18n-react";
import { useBackend } from "@/contexts/backend";
import { Dialog } from "primereact/dialog";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import {
faCheck,
faCircle,
faCircleNotch,
faConstruction,
faExternalLink,
faPersonDigging,
faStars,
faTag,
} from "@fortawesome/pro-solid-svg-icons";
import Markdown from "react-markdown";
import Button from "./button";
import Link from "next/link";
import SmallInfoCard from "./small_info_card";
import { env } from "next-runtime-env";

export default function VersionModal({
visible,
setVisible,
autoOpen,
}: {
visible: boolean;
setVisible: (boolean) => void;
autoOpen?: boolean;
}) {
const { LL, locale } = useI18nContext();

// biome-ignore lint/suspicious/noExplicitAny: Type not known, github API response
const [releases, setReleases] = useState<any[]>([]);
const [version, setVersion] = useState<string>("DEV");

useEffect(() => {
const v = env("NEXT_PUBLIC_VERSION") || "DEV";
setVersion(v);

if (
localStorage.getItem("munify_version_modal_seen_with_version") !== v &&
autoOpen
) {
setVisible(true);
localStorage.setItem("munify_version_modal_seen_with_version", v);
}

fetch(
"https://api.github.com/repos/deutschemodelunitednations/munify/releases",
)
.then((res) => res.json())
.then((data) => {
setReleases(data);
})
.catch((err) => {
console.error(err);
});
}, []);

return (
<>
<Dialog
header={
<>
<FontAwesomeIcon icon={faStars} className="mr-3 text-orange-400" />
{LL.version.VERSION_MODAL_TITLE()}
</>
}
visible={visible}
style={{ width: "70vw" }}
onHide={() => setVisible(false)}
dismissableMask
>
<h1 className="text-3xl font-bold text-slate-900 mb-4">
{LL.version.VERSION()}
</h1>
<div className="text-2xl font-mono font-bold text-white py-4 px-4 rounded-lg bg-primary-500 flex justify-center items-center mb-2">
<FontAwesomeIcon icon={faTag} className="mr-3" />
{version}
</div>
{version !== releases[0]?.name ? (
version === "DEV" ? (
<SmallInfoCard icon={faConstruction}>
<div className="flex flex-col">
<h3 className="font-bold">
{LL.version.DEVELOPMENT_VERSION()}
</h3>
<p>{LL.version.DEVELOPMENT_VERSION_TEXT()}</p>
</div>
</SmallInfoCard>
) : (
<SmallInfoCard icon={faStars}>
<div className="flex flex-col">
<h3 className="font-bold">
{LL.version.NEW_VERSION_AVAILABLE()}
</h3>
<p>{LL.version.NEW_VERSION_AVAILABLE_TEXT()}</p>
</div>
</SmallInfoCard>
)
) : (
<SmallInfoCard
icon={faCheck}
classNameForContentBox="bg-green-500"
classNameForIconBox="bg-green-500 text-green-500 border-green-500"
>
<div className="flex flex-col">
<h3 className="font-bold">{LL.version.LATEST_VERSION()}</h3>
<p>{LL.version.LATEST_VERSION_TEXT()}</p>
</div>
</SmallInfoCard>
)}

<h1 className="text-3xl font-bold text-slate-900 mb-2 mt-10">
{LL.version.CHANGELOG()}
</h1>
<p className="text-slate-900 mb-4 text-sm">
{LL.version.CHANGELOG_TEXT()}
</p>
<div className="flex flex-col gap-2">
{releases.length > 0 ? (
releases.map((release, i) => {
if (i > 5) return null;
return (
<div
key={release.id}
className="p-4 bg-primary-950 rounded-lg flex flex-col gap-2 justify-start items-start"
>
<div className="flex gap-2 items-start justify-between w-full mb-2">
<Link
className="text-2xl font-mono font-bold text-white py-2 px-4 rounded-lg bg-primary-500 flex justify-center items-center"
href={release.html_url}
>
<FontAwesomeIcon icon={faTag} className="mr-3" />
{release.name}
</Link>
<div className="text-slate-900">
{new Date(release.published_at).toLocaleString(locale, {
dateStyle: "medium",
timeStyle: "short",
})}
</div>
</div>
<Markdown className="prose prose-sm w-full overflow-x-scroll">
{release.body}
</Markdown>
</div>
);
})
) : (
<FontAwesomeIcon icon={faCircleNotch} spin />
)}
<Button
label={LL.version.ALL_RELEASES()}
onClick={() =>
window.open(
"https://github.com/deutschemodelunitednations/munify/releases",
)
}
faIcon={faExternalLink}
className="mt-4"
/>
</div>
</Dialog>
</>
);
}
15 changes: 15 additions & 0 deletions chase/frontend/i18n/de/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ const de = {
CONTRIBUTE_TEXT:
"CHASE ist ein wichtiger Bestandteil der Open-Source-Initiative 'MUNify' von DMUN. Das bedeutet, dass jeder, der möchte, zur Entwicklung beitragen kann. Wir freuen uns über jede Hilfe, die wir bekommen können. Wenn Sie also Erfahrung im Web-Development haben, oder einfach nur neue Skills lernen und mithelfen möchten, schauen Sie doch mal auf unserem GitHub vorbei!",
CONTRIBUTE_BUTTON_LABEL: "MUNify auf GitHub",
VERSION_BUTTON: "Version und Änderungen",
footer: {
sitemap: {
TITEL: "Sitemap",
Expand Down Expand Up @@ -681,6 +682,20 @@ const de = {
REPLY_VIA_EMAIL: "Antworten per E-Mail",
},
},
version: {
VERSION_MODAL_TITLE: "Version und Änderungsprotokoll",
VERSION: "Version",
CHANGELOG: "Änderungsprotokoll",
CHANGELOG_TEXT:
"Dieses Änderungsprotokoll zeigt die Änderungen in der aktuellen und den letzten 4 Versionen. Aktuell ist das Änderungsprotokoll ausschließlich auf Englisch verfügbar. Für weitere Informationen besuchen Sie unser GitHub-Repository, indem Sie auf den Link unten klicken.",
ALL_RELEASES: "Alle Versionen",
NEW_VERSION_AVAILABLE: "Neue Version verfügbar",
NEW_VERSION_AVAILABLE_TEXT: "Bitte wenden Sie sich an den Administrator, um die App zu aktualisieren.",
LATEST_VERSION: "Neueste Version",
LATEST_VERSION_TEXT: "Sie verwenden die neueste Version von CHASE.",
DEVELOPMENT_VERSION: "Entwicklerversion",
DEVELOPMENT_VERSION_TEXT: "Sie verwenden eine Entwicklerversion von CHASE.",
},
} satisfies Translation;

export default de;
Loading

0 comments on commit 8ca82db

Please sign in to comment.