feat: add changelog modal on visit if new version is detected

This commit is contained in:
Kentai Radiquum 2024-08-12 03:18:41 +05:00
parent 04c072fba7
commit 8bcd548ae3
Signed by: Radiquum
GPG key ID: 858E8EE696525EED
11 changed files with 1137 additions and 22 deletions

View file

@ -1,10 +1,5 @@
# Список TODO для AniX V3
## Важное
- [ ] Кнопка сброса всех настроек
- [ ] Список изменений при входе
## Страницы
### Поиск

View file

@ -6,15 +6,34 @@ import { Inter } from "next/font/google";
import { useEffect, useState } from "react";
import { Button, Modal } from "flowbite-react";
import { Spinner } from "./components/Spinner/Spinner";
import { ChangelogModal } from "#/components/ChangelogModal/ChangelogModal";
const inter = Inter({ subsets: ["latin"] });
export const App = (props) => {
const preferencesStore = usePreferencesStore();
const userStore = useUserStore((state) => state);
const [showChangelog, setShowChangelog] = useState(false);
const [currentVersion, setCurrentVersion] = useState("");
const [previousVersions, setPreviousVersions] = useState([]);
async function _checkVersion() {
const res = await fetch("/api/version");
const data = await res.json();
if (data.version !== preferencesStore.params.version) {
setShowChangelog(true);
setCurrentVersion(data.version);
setPreviousVersions(data.previous);
}
console.log(data.version, preferencesStore.params.version);
}
useEffect(() => {
userStore.checkAuth();
}, []);
if (preferencesStore._hasHydrated) {
_checkVersion();
userStore.checkAuth();
}
}, [preferencesStore._hasHydrated]);
if (!preferencesStore._hasHydrated && !userStore._hasHydrated) {
return (
@ -42,7 +61,19 @@ export const App = (props) => {
>
<Navbar />
{props.children}
<Modal show={preferencesStore.params.isFirstLaunch}>
<ChangelogModal
isOpen={showChangelog && preferencesStore.flags.showChangelog}
setIsOpen={() => {
setShowChangelog(false);
preferencesStore.setParams({ version: currentVersion });
}}
version={currentVersion}
previousVersions={previousVersions}
/>
<Modal
show={preferencesStore.params.isFirstLaunch}
onClose={() => preferencesStore.setParams({ isFirstLaunch: false })}
>
<Modal.Header>Внимание</Modal.Header>
<Modal.Body>
<p>
@ -61,9 +92,7 @@ export const App = (props) => {
<Modal.Footer>
<Button
color={"blue"}
onClick={() => {
preferencesStore.setParams({ isFirstLaunch: false });
}}
onClick={() => preferencesStore.setParams({ isFirstLaunch: false })}
>
Принимаю
</Button>

17
app/api/version/route.ts Normal file
View file

@ -0,0 +1,17 @@
import { NextResponse } from "next/server";
import * as fs from "node:fs";
import * as path from "node:path";
export async function GET() {
const directoryPath = path.join(process.cwd(), "public/changelog");
const files = fs.readdirSync(directoryPath);
const current = "3.0.1";
const previous = [];
files.forEach((file) => {
if (file != `${current}.md`) {
previous.push(file.replace(".md", ""));
}
});
return NextResponse.json({ version: current, previous: previous });
}

View file

@ -0,0 +1,16 @@
.markdown h1 {
font-size: 1.5rem;
font-weight: 700;
}
.markdown h2 {
font-size: 1rem;
font-weight: 700;
margin-block: 1rem 0.25rem;
}
.markdown ul {
list-style-type: disc;
-webkit-padding-start: 20px;
padding-inline-start: 20px;
}

View file

@ -0,0 +1,68 @@
import { Modal, Button, Accordion } from "flowbite-react";
import Markdown from "markdown-to-jsx";
import { useEffect, useState } from "react";
import Styles from "./ChangelogModal.module.css";
async function _fetchVersionChangelog(version: string) {
const res = await fetch(`/changelog/${version}.md`);
return await res.text();
}
export const ChangelogModal = (props: {
isOpen: boolean;
setIsOpen: any;
version: string;
previousVersions: Array<string>;
}) => {
const [currentVersionChangelog, setCurrentVersionChangelog] = useState("");
const [previousVersionsChangelog, setPreviousVersionsChangelog] = useState<
Record<string, string>
>({});
useEffect(() => {
_fetchVersionChangelog(props.version).then((data) => {
setCurrentVersionChangelog(data);
});
if (props.previousVersions.length > 0) {
props.previousVersions.forEach((version) => {
_fetchVersionChangelog(version).then((data) => {
setPreviousVersionsChangelog((prev) => {
return {
...prev,
[version]: data,
};
});
});
});
}
}, [props.isOpen]);
return (
<Modal
show={props.isOpen}
onClose={() => props.setIsOpen(false)}
>
<Modal.Header>Список изменений v{props.version}</Modal.Header>
<Modal.Body>
<Markdown className={Styles.markdown}>
{currentVersionChangelog}
</Markdown>
{Object.keys(previousVersionsChangelog).length > 0 && (
<Accordion collapseAll={true} className="mt-4">
{Object.entries(previousVersionsChangelog).map(
([version, changelog]) => (
<Accordion.Panel key={version}>
<Accordion.Title>Список изменений v{version}</Accordion.Title>
<Accordion.Content>
<Markdown className={Styles.markdown}>{changelog}</Markdown>
</Accordion.Content>
</Accordion.Panel>
)
)}
</Accordion>
)}
</Modal.Body>
</Modal>
);
};

View file

@ -7,8 +7,8 @@ import {
Dropdown,
Modal,
Button,
DarkThemeToggle,
useThemeMode,
ToggleSwitch,
} from "flowbite-react";
import { useState } from "react";
@ -194,7 +194,9 @@ export const Navbar = () => {
>
<Dropdown.Item className="text-sm md:text-base">
<Link
href={pathname != "/login" ? `/login?redirect=${pathname}` : "#"}
href={
pathname != "/login" ? `/login?redirect=${pathname}` : "#"
}
className="flex items-center gap-1"
>
<span
@ -267,6 +269,29 @@ const SettingsModal = (props: { isOpen: boolean; setIsOpen: any }) => {
</Button>
</Button.Group>
</div>
<div className="flex items-center justify-between">
<p className="font-bold dark:text-white">
Показывать список изменений
</p>
<ToggleSwitch
color="blue"
theme={{
toggle: {
checked: {
color: {
blue: "border-blue-700 bg-blue-700",
},
},
},
}}
onChange={() =>
preferenceStore.setFlags({
showChangelog: !preferenceStore.flags.showChangelog,
})
}
checked={preferenceStore.flags.showChangelog}
/>
</div>
</div>
</Modal.Body>
</Modal>

View file

@ -1,16 +1,18 @@
"use client";
import { create } from "zustand";
import { persist } from "zustand/middleware";
import { deepmerge } from "deepmerge-ts";
interface preferencesState {
_hasHydrated: boolean;
flags: {
// saveSearchHistory: boolean;
saveWatchHistory: boolean;
// theme: "light" | "dark" | "black" | "system";
saveWatchHistory?: boolean;
showChangelog?: boolean;
};
params: {
isFirstLaunch: boolean;
isFirstLaunch?: boolean;
version?: string;
// color: {
// primary: string;
// secondary: string;
@ -29,10 +31,11 @@ export const usePreferencesStore = create<preferencesState>()(
flags: {
// saveSearchHistory: true,
saveWatchHistory: true,
// theme: "light",
showChangelog: true,
},
params: {
isFirstLaunch: true,
version: "3.0.0",
},
setHasHydrated: (state) => {
set({
@ -40,10 +43,10 @@ export const usePreferencesStore = create<preferencesState>()(
});
},
setFlags(flags) {
set({ flags });
set({ flags: { ...get().flags, ...flags } });
},
setParams(params) {
set({ params });
set({ params: { ...get().params, ...params } });
},
}),
{
@ -51,6 +54,9 @@ export const usePreferencesStore = create<preferencesState>()(
onRehydrateStorage: (state) => {
return () => state.setHasHydrated(true);
},
merge: (persistedState , currentState) => {
return deepmerge(currentState as preferencesState, persistedState as preferencesState);
}
}
)
);

929
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -9,8 +9,10 @@
"lint": "next lint"
},
"dependencies": {
"deepmerge-ts": "^7.1.0",
"flowbite": "^2.4.1",
"flowbite-react": "^0.10.1",
"markdown-to-jsx": "^7.4.7",
"next": "14.2.5",
"react": "^18",
"react-dom": "^18",
@ -26,6 +28,7 @@
"@iconify/tailwind": "^1.1.1",
"@types/node": "20.14.12",
"@types/react": "18.3.3",
"copy-webpack-plugin": "^12.0.2",
"eslint": "^8",
"eslint-config-next": "14.2.5",
"postcss": "^8",

19
public/changelog/3.0.0.md Normal file
View file

@ -0,0 +1,19 @@
# 3.0.0
Это обновление приносит новый интерфейс, а так-же новую систему проксирования запросов API к серверу Anixart.
## Добавлено
- Больше информации при просмотре страниц на карточке релиза (рейтинг, статус, категория и т.д.)
- адаптация под мобильные устройства
- возможность смотреть и ставить оценки релизу
- больше информации о самом релизе
- просмотр комментариев, их оценка. возможность комментирования и ответа на комментарии.
- добавлена страница франшиз\полных связанных релизов
- поиск по автору, режиссёру, студии и жанрам
- возможность установить сайт как веб приложение
## Удалено
- материал ю
- не стандартная история поиска

14
public/changelog/3.0.1.md Normal file
View file

@ -0,0 +1,14 @@
# 3.0.1
## Добавлено
- Новое уведомление о бане пользователя администрацией
- Дисклеймер при первом открытии
- Список изменений при открытии
## Исправлено
- Вид кнопок социальных сетей в профиле
- Сжатие аватарки пользователя при слишком длинном статусе
- Перенос текста статуса на новые линии
- Загрузка пока авторизация не проверена