mirror of
https://github.com/StepanovPlaton/torrent_frontend.git
synced 2026-04-03 20:30:48 +04:00
Refactoring
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import { GameService, GameType, isSection, ItemService } from "@/entities/item";
|
import { ItemService } from "@/entities/item";
|
||||||
import { ItemCard } from "@/features/itemCard";
|
import { SectionService } from "@/features/sections";
|
||||||
|
import { ItemCard } from "@/widgets/itemCard";
|
||||||
import { ItemInfo } from "@/widgets/itemInfo";
|
import { ItemInfo } from "@/widgets/itemInfo";
|
||||||
import { Section } from "@/widgets/section";
|
import { Section } from "@/widgets/section";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
@@ -9,13 +10,17 @@ export default async function Item({
|
|||||||
}: {
|
}: {
|
||||||
params: { section: string; item_id: number };
|
params: { section: string; item_id: number };
|
||||||
}) {
|
}) {
|
||||||
const game = isSection(section)
|
const game = SectionService.isSection(section)
|
||||||
? await ItemService.itemSections[section].service.Get(item_id)
|
? await ItemService.itemsConfiguration[
|
||||||
|
SectionService.sectionsConfiguration[section].itemType
|
||||||
|
].service.Get(item_id)
|
||||||
: redirect("/");
|
: redirect("/");
|
||||||
|
|
||||||
const cards =
|
const cards =
|
||||||
isSection(section) &&
|
SectionService.isSection(section) &&
|
||||||
(await ItemService.itemSections[section].service.GetCards());
|
(await ItemService.itemsConfiguration[
|
||||||
|
SectionService.sectionsConfiguration[section].itemType
|
||||||
|
].service.GetCards());
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -24,14 +29,15 @@ export default async function Item({
|
|||||||
{cards && (
|
{cards && (
|
||||||
<Section
|
<Section
|
||||||
name={
|
name={
|
||||||
isSection(section)
|
SectionService.isSection(section)
|
||||||
? ItemService.itemSections[section].popularSubsectionName
|
? SectionService.sectionsConfiguration[section]
|
||||||
|
.popularSubsectionName
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
link={isSection(section) ? `/${section}` : undefined}
|
link={SectionService.isSection(section) ? `/${section}` : undefined}
|
||||||
invite_text={
|
invite_text={
|
||||||
isSection(section)
|
SectionService.isSection(section)
|
||||||
? ItemService.itemSections[section].sectionInviteText
|
? SectionService.sectionsConfiguration[section].sectionInviteText
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,21 +1,22 @@
|
|||||||
import { GameService, isSection, ItemService } from "@/entities/item";
|
import { ItemCard } from "@/widgets/itemCard";
|
||||||
import { ItemCard } from "@/features/itemCard";
|
|
||||||
import { ItemInfo } from "@/widgets/itemInfo";
|
import { ItemInfo } from "@/widgets/itemInfo";
|
||||||
import { Section } from "@/widgets/section";
|
import { Section } from "@/widgets/section";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
import { Metadata } from "next";
|
import { Metadata } from "next";
|
||||||
|
import { SectionService } from "@/features/sections";
|
||||||
|
import { ItemService } from "@/entities/item";
|
||||||
|
|
||||||
export async function generateMetadata({
|
export async function generateMetadata({
|
||||||
params: { section },
|
params: { section },
|
||||||
}: {
|
}: {
|
||||||
params: { section: string };
|
params: { section: string };
|
||||||
}): Promise<Metadata> {
|
}): Promise<Metadata> {
|
||||||
if (!isSection(section)) {
|
if (!SectionService.isSection(section)) {
|
||||||
redirect("/");
|
redirect("/");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
title: `.Torrent: ${ItemService.itemSections[section].addItemText}`,
|
title: `.Torrent: ${SectionService.sectionsConfiguration[section].addItemText}`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,13 +25,17 @@ export default async function AddItem({
|
|||||||
}: {
|
}: {
|
||||||
params: { section: string };
|
params: { section: string };
|
||||||
}) {
|
}) {
|
||||||
const emptyItem = isSection(section)
|
const emptyItem = SectionService.isSection(section)
|
||||||
? await ItemService.itemSections[section].service.GetEmpty()
|
? await ItemService.itemsConfiguration[
|
||||||
|
SectionService.sectionsConfiguration[section].itemType
|
||||||
|
].service.GetEmpty()
|
||||||
: redirect("/");
|
: redirect("/");
|
||||||
|
|
||||||
const cards =
|
const cards =
|
||||||
isSection(section) &&
|
SectionService.isSection(section) &&
|
||||||
(await ItemService.itemSections[section].service.GetCards());
|
(await ItemService.itemsConfiguration[
|
||||||
|
SectionService.sectionsConfiguration[section].itemType
|
||||||
|
].service.GetCards());
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -39,14 +44,15 @@ export default async function AddItem({
|
|||||||
{cards && (
|
{cards && (
|
||||||
<Section
|
<Section
|
||||||
name={
|
name={
|
||||||
isSection(section)
|
SectionService.isSection(section)
|
||||||
? ItemService.itemSections[section].popularSubsectionName
|
? SectionService.sectionsConfiguration[section]
|
||||||
|
.popularSubsectionName
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
link={isSection(section) ? `/${section}` : undefined}
|
link={SectionService.isSection(section) ? `/${section}` : undefined}
|
||||||
invite_text={
|
invite_text={
|
||||||
isSection(section)
|
SectionService.isSection(section)
|
||||||
? ItemService.itemSections[section].sectionInviteText
|
? SectionService.sectionsConfiguration[section].sectionInviteText
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,21 +1,25 @@
|
|||||||
import { isSection, ItemService, MovieService } from "@/entities/item";
|
import { isSection, ItemService, MovieService } from "@/entities/item";
|
||||||
import { ItemCard } from "@/features/itemCard";
|
import { ItemCard } from "@/widgets/itemCard";
|
||||||
import { Section } from "@/widgets/section";
|
import { Section } from "@/widgets/section";
|
||||||
import { redirect } from "next/navigation";
|
import { redirect } from "next/navigation";
|
||||||
import { Metadata } from "next";
|
import { Metadata } from "next";
|
||||||
|
import { SectionService } from "@/features/sections";
|
||||||
|
|
||||||
export async function generateMetadata({
|
export async function generateMetadata({
|
||||||
params: { section },
|
params: { section },
|
||||||
}: {
|
}: {
|
||||||
params: { section: string };
|
params: { section: string };
|
||||||
}): Promise<Metadata> {
|
}): Promise<Metadata> {
|
||||||
if (!isSection(section)) {
|
if (!SectionService.isSection(section)) {
|
||||||
redirect("/");
|
redirect("/");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
title: `.Torrent: ${ItemService.itemSections[section].sectionName}`,
|
title: `.Torrent: ${SectionService.sectionsConfiguration[section].sectionName}`,
|
||||||
description: `.Torrent: ${ItemService.itemSections[section].sectionName} - ${ItemService.itemSections[section].sectionName}`,
|
description:
|
||||||
|
`.Torrent: ` +
|
||||||
|
`${SectionService.sectionsConfiguration[section].sectionName} - ` +
|
||||||
|
`${SectionService.sectionsConfiguration[section].sectionDescription}`,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,8 +28,10 @@ export default async function SectionPage({
|
|||||||
}: {
|
}: {
|
||||||
params: { section: string };
|
params: { section: string };
|
||||||
}) {
|
}) {
|
||||||
const cards = isSection(section)
|
const cards = SectionService.isSection(section)
|
||||||
? await ItemService.itemSections[section].service.GetCards()
|
? await ItemService.itemsConfiguration[
|
||||||
|
SectionService.sectionsConfiguration[section].itemType
|
||||||
|
].service.GetCards()
|
||||||
: redirect("/");
|
: redirect("/");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
import {
|
import { ItemCardType, ItemService } from "@/entities/item";
|
||||||
isSection,
|
import { ItemCard } from "@/widgets/itemCard";
|
||||||
ItemCardType,
|
import { SectionService, SectionType } from "@/features/sections";
|
||||||
ItemSections,
|
|
||||||
ItemSectionsType,
|
|
||||||
ItemService,
|
|
||||||
} from "@/entities/item";
|
|
||||||
import { ItemCard } from "@/features/itemCard";
|
|
||||||
import { Section } from "@/widgets/section";
|
import { Section } from "@/widgets/section";
|
||||||
import { Metadata } from "next";
|
import { Metadata } from "next";
|
||||||
|
|
||||||
@@ -16,24 +11,31 @@ export const metadata: Metadata = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default async function Home() {
|
export default async function Home() {
|
||||||
const cards: { [k in ItemSectionsType]?: ItemCardType[] | null } = {};
|
const cards: { [k in SectionType]?: ItemCardType[] | null } = {};
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
ItemSections.map(async (section) => {
|
SectionService.sections.map(async (section) => {
|
||||||
cards[section] = await ItemService.itemSections[
|
cards[section] = await ItemService.itemsConfiguration[
|
||||||
section
|
SectionService.sectionsConfiguration[section].itemType
|
||||||
].service.GetCards();
|
].service.GetCards();
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{ItemSections.map((section) => (
|
{SectionService.sections.map((section) => (
|
||||||
<section key={section}>
|
<section key={section}>
|
||||||
{cards[section] && cards[section].length > 0 && (
|
{cards[section] && cards[section].length > 0 && (
|
||||||
<Section
|
<Section
|
||||||
name={ItemService.itemSections[section].popularSubsectionName}
|
name={
|
||||||
link={isSection(section) ? `/${section}` : undefined}
|
SectionService.sectionsConfiguration[section]
|
||||||
invite_text={ItemService.itemSections[section].sectionInviteText}
|
.popularSubsectionName
|
||||||
|
}
|
||||||
|
link={
|
||||||
|
SectionService.isSection(section) ? `/${section}` : undefined
|
||||||
|
}
|
||||||
|
invite_text={
|
||||||
|
SectionService.sectionsConfiguration[section].sectionInviteText
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{cards[section].map((card) => (
|
{cards[section].map((card) => (
|
||||||
<ItemCard key={card.id} card={card} />
|
<ItemCard key={card.id} card={card} />
|
||||||
|
|||||||
@@ -85,20 +85,16 @@ import { ItemService } from "./item";
|
|||||||
export { ItemService };
|
export { ItemService };
|
||||||
|
|
||||||
import {
|
import {
|
||||||
isSection,
|
TypesOfItems,
|
||||||
|
type IItemService,
|
||||||
type ItemType,
|
type ItemType,
|
||||||
type ItemCardType,
|
type ItemCardType,
|
||||||
type ItemCreateType,
|
type ItemCreateType,
|
||||||
type TypesOfItems,
|
|
||||||
type ItemSectionsType,
|
|
||||||
ItemSections,
|
|
||||||
} from "./types";
|
} from "./types";
|
||||||
export {
|
export {
|
||||||
isSection,
|
TypesOfItems,
|
||||||
|
type IItemService,
|
||||||
type ItemType,
|
type ItemType,
|
||||||
type ItemCardType,
|
type ItemCardType,
|
||||||
type ItemCreateType,
|
type ItemCreateType,
|
||||||
type TypesOfItems,
|
|
||||||
type ItemSectionsType,
|
|
||||||
ItemSections,
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,10 +7,8 @@ import { audiobookCreateSchema } from "./audiobook/schemas/audiobook";
|
|||||||
import { AudiobookService } from "./audiobook/audiobook";
|
import { AudiobookService } from "./audiobook/audiobook";
|
||||||
import {
|
import {
|
||||||
IItemService,
|
IItemService,
|
||||||
ItemCardType,
|
|
||||||
ItemCreateType,
|
ItemCreateType,
|
||||||
ItemPropertiesDescriptionType,
|
ItemPropertiesDescriptionType,
|
||||||
ItemSectionsType,
|
|
||||||
ItemType,
|
ItemType,
|
||||||
TypesOfItems,
|
TypesOfItems,
|
||||||
UnionItemType,
|
UnionItemType,
|
||||||
@@ -18,9 +16,8 @@ import {
|
|||||||
import { EraseCacheByTags } from "@/shared/utils/http";
|
import { EraseCacheByTags } from "@/shared/utils/http";
|
||||||
|
|
||||||
export abstract class ItemService {
|
export abstract class ItemService {
|
||||||
private static get itemsConfiguration(): {
|
static get itemsConfiguration(): {
|
||||||
[k in TypesOfItems]: {
|
[k in TypesOfItems]: {
|
||||||
sectionUrl: ItemSectionsType;
|
|
||||||
formResolver: ZodSchema;
|
formResolver: ZodSchema;
|
||||||
propertiesDescription: ItemPropertiesDescriptionType<UnionItemType>;
|
propertiesDescription: ItemPropertiesDescriptionType<UnionItemType>;
|
||||||
service: IItemService;
|
service: IItemService;
|
||||||
@@ -28,19 +25,16 @@ export abstract class ItemService {
|
|||||||
} {
|
} {
|
||||||
return {
|
return {
|
||||||
[TypesOfItems.game]: {
|
[TypesOfItems.game]: {
|
||||||
sectionUrl: "games",
|
|
||||||
formResolver: gameCreateSchema,
|
formResolver: gameCreateSchema,
|
||||||
propertiesDescription: GameService.propertiesDescription,
|
propertiesDescription: GameService.propertiesDescription,
|
||||||
service: GameService,
|
service: GameService,
|
||||||
},
|
},
|
||||||
[TypesOfItems.movie]: {
|
[TypesOfItems.movie]: {
|
||||||
sectionUrl: "movies",
|
|
||||||
formResolver: movieCreateSchema,
|
formResolver: movieCreateSchema,
|
||||||
propertiesDescription: MovieService.propertiesDescription,
|
propertiesDescription: MovieService.propertiesDescription,
|
||||||
service: MovieService,
|
service: MovieService,
|
||||||
},
|
},
|
||||||
[TypesOfItems.audiobook]: {
|
[TypesOfItems.audiobook]: {
|
||||||
sectionUrl: "audiobooks",
|
|
||||||
formResolver: audiobookCreateSchema,
|
formResolver: audiobookCreateSchema,
|
||||||
propertiesDescription: AudiobookService.propertiesDescription,
|
propertiesDescription: AudiobookService.propertiesDescription,
|
||||||
service: AudiobookService,
|
service: AudiobookService,
|
||||||
@@ -48,76 +42,12 @@ export abstract class ItemService {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static get itemSections(): {
|
|
||||||
[k in ItemSectionsType]: {
|
|
||||||
sectionName: string;
|
|
||||||
itemType: TypesOfItems;
|
|
||||||
popularSubsectionName: string;
|
|
||||||
sectionInviteText: string;
|
|
||||||
addItemText: string;
|
|
||||||
sectionDescription: string;
|
|
||||||
service: IItemService;
|
|
||||||
};
|
|
||||||
} {
|
|
||||||
return {
|
|
||||||
games: {
|
|
||||||
sectionName: "Игры",
|
|
||||||
itemType: TypesOfItems.game,
|
|
||||||
popularSubsectionName: "Популярные игры",
|
|
||||||
sectionInviteText: 'Перейти в раздел "Игры"',
|
|
||||||
addItemText: "Добавить игру",
|
|
||||||
sectionDescription:
|
|
||||||
"каталог .torrent файлов для обмена актуальными версиями популярных игр",
|
|
||||||
service: GameService,
|
|
||||||
},
|
|
||||||
movies: {
|
|
||||||
sectionName: "Фильмы",
|
|
||||||
itemType: TypesOfItems.movie,
|
|
||||||
popularSubsectionName: "Популярные фильмы",
|
|
||||||
sectionInviteText: 'Перейти в раздел "Фильмы"',
|
|
||||||
addItemText: "Добавить фильм",
|
|
||||||
sectionDescription:
|
|
||||||
"каталог .torrent файлов для обмена популярными фильмами в лучшем качестве",
|
|
||||||
service: MovieService,
|
|
||||||
},
|
|
||||||
audiobooks: {
|
|
||||||
sectionName: "Аудиокниги",
|
|
||||||
itemType: TypesOfItems.audiobook,
|
|
||||||
popularSubsectionName: "Популярные аудиокниги",
|
|
||||||
sectionInviteText: 'Перейти в раздел "Аудиокниги"',
|
|
||||||
addItemText: "Добавить аудиокнигу",
|
|
||||||
sectionDescription:
|
|
||||||
"каталог .torrent файлов для обмена популярными аудиокнигами любимых авторов",
|
|
||||||
service: AudiobookService,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public static isExistingItem(
|
public static isExistingItem(
|
||||||
item: ItemCreateType | ItemType
|
item: ItemCreateType | ItemType
|
||||||
): item is ItemType {
|
): item is ItemType {
|
||||||
return (item as ItemType).id !== undefined;
|
return (item as ItemType).id !== undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GetFormResolver(
|
|
||||||
item: ItemCardType | ItemCreateType | ItemType
|
|
||||||
) {
|
|
||||||
return this.itemsConfiguration[item.type].formResolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GetSectionUrlByItemType(
|
|
||||||
item: ItemCardType | ItemCreateType | ItemType
|
|
||||||
) {
|
|
||||||
return this.itemsConfiguration[item.type].sectionUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static GetPropertiesDescriptionForItem<
|
|
||||||
T extends ItemType | ItemCreateType
|
|
||||||
>(item: T) {
|
|
||||||
return this.itemsConfiguration[item.type]
|
|
||||||
.propertiesDescription as ItemPropertiesDescriptionType<T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async AddItem(itemInfo: ItemCreateType) {
|
public static async AddItem(itemInfo: ItemCreateType) {
|
||||||
const item = await this.itemsConfiguration[itemInfo.type].service.Add(
|
const item = await this.itemsConfiguration[itemInfo.type].service.Add(
|
||||||
itemInfo
|
itemInfo
|
||||||
|
|||||||
@@ -16,30 +16,12 @@ export type ItemCreateType =
|
|||||||
| AudiobookCreateType;
|
| AudiobookCreateType;
|
||||||
|
|
||||||
export type UnionItemType = GameType & MovieType & AudiobookType;
|
export type UnionItemType = GameType & MovieType & AudiobookType;
|
||||||
export type UnionItemCardType = GameCardType &
|
|
||||||
MovieCardType &
|
|
||||||
AudiobookCardType;
|
|
||||||
export type UnionItemCreateType = GameCreateType &
|
|
||||||
MovieCreateType &
|
|
||||||
AudiobookCreateType;
|
|
||||||
|
|
||||||
export enum TypesOfItems {
|
export enum TypesOfItems {
|
||||||
game,
|
game,
|
||||||
movie,
|
movie,
|
||||||
audiobook,
|
audiobook,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ItemSectionsType = "games" | "movies" | "audiobooks";
|
|
||||||
export const ItemSections = [
|
|
||||||
"games",
|
|
||||||
"movies",
|
|
||||||
"audiobooks",
|
|
||||||
] as ItemSectionsType[];
|
|
||||||
|
|
||||||
export const isSection = (a: string): a is ItemSectionsType => {
|
|
||||||
return (ItemSections as string[]).includes(a);
|
|
||||||
};
|
|
||||||
|
|
||||||
export type ItemPropertiesDescriptionType<T extends ItemType | ItemCreateType> =
|
export type ItemPropertiesDescriptionType<T extends ItemType | ItemCreateType> =
|
||||||
{
|
{
|
||||||
name: string;
|
name: string;
|
||||||
|
|||||||
2
src/features/sections/index.ts
Normal file
2
src/features/sections/index.ts
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
import { SectionService, type SectionType } from "./sections";
|
||||||
|
export { SectionService, type SectionType };
|
||||||
64
src/features/sections/sections.ts
Normal file
64
src/features/sections/sections.ts
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
import { TypesOfItems } from "@/entities/item";
|
||||||
|
|
||||||
|
export type SectionType = (typeof SectionService.sections)[number];
|
||||||
|
|
||||||
|
export abstract class SectionService {
|
||||||
|
static get itemTypeToSection(): { [k in TypesOfItems]: SectionType } {
|
||||||
|
return {
|
||||||
|
[TypesOfItems.game]: "games",
|
||||||
|
[TypesOfItems.movie]: "movies",
|
||||||
|
[TypesOfItems.audiobook]: "audiobooks",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static get sectionsConfiguration(): {
|
||||||
|
[k in SectionType]: {
|
||||||
|
sectionName: string;
|
||||||
|
sectionUrl: string;
|
||||||
|
itemType: TypesOfItems;
|
||||||
|
popularSubsectionName: string;
|
||||||
|
sectionInviteText: string;
|
||||||
|
addItemText: string;
|
||||||
|
sectionDescription: string;
|
||||||
|
};
|
||||||
|
} {
|
||||||
|
return {
|
||||||
|
games: {
|
||||||
|
sectionName: "Игры",
|
||||||
|
sectionUrl: "games",
|
||||||
|
itemType: TypesOfItems.game,
|
||||||
|
popularSubsectionName: "Популярные игры",
|
||||||
|
sectionInviteText: 'Перейти в раздел "Игры"',
|
||||||
|
addItemText: "Добавить игру",
|
||||||
|
sectionDescription:
|
||||||
|
"каталог .torrent файлов для обмена актуальными версиями популярных игр",
|
||||||
|
},
|
||||||
|
movies: {
|
||||||
|
sectionName: "Фильмы",
|
||||||
|
sectionUrl: "movies",
|
||||||
|
itemType: TypesOfItems.movie,
|
||||||
|
popularSubsectionName: "Популярные фильмы",
|
||||||
|
sectionInviteText: 'Перейти в раздел "Фильмы"',
|
||||||
|
addItemText: "Добавить фильм",
|
||||||
|
sectionDescription:
|
||||||
|
"каталог .torrent файлов для обмена популярными фильмами в лучшем качестве",
|
||||||
|
},
|
||||||
|
audiobooks: {
|
||||||
|
sectionName: "Аудиокниги",
|
||||||
|
sectionUrl: "audiobooks",
|
||||||
|
itemType: TypesOfItems.audiobook,
|
||||||
|
popularSubsectionName: "Популярные аудиокниги",
|
||||||
|
sectionInviteText: 'Перейти в раздел "Аудиокниги"',
|
||||||
|
addItemText: "Добавить аудиокнигу",
|
||||||
|
sectionDescription:
|
||||||
|
"каталог .torrent файлов для обмена популярными аудиокнигами любимых авторов",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
static sections = ["games", "movies", "audiobooks"] as const;
|
||||||
|
|
||||||
|
static isSection = (a: string): a is SectionType => {
|
||||||
|
return this.sections.includes(a as SectionType);
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -7,7 +7,7 @@ import useSWR, { mutate } from "swr";
|
|||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import Cookies from "js-cookie";
|
import Cookies from "js-cookie";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { ItemService } from "@/entities/item";
|
import { SectionService } from "../sections";
|
||||||
|
|
||||||
export const UserActivities = () => {
|
export const UserActivities = () => {
|
||||||
const { data: me } = useSWR("user", () => UserService.IdentifyYourself());
|
const { data: me } = useSWR("user", () => UserService.IdentifyYourself());
|
||||||
@@ -39,14 +39,13 @@ export const UserActivities = () => {
|
|||||||
{[
|
{[
|
||||||
{
|
{
|
||||||
group: "Добавить:",
|
group: "Добавить:",
|
||||||
items: Object.entries(ItemService.itemSections).map(
|
items: SectionService.sections.map((section) => {
|
||||||
([sectionId, section]) => {
|
|
||||||
return {
|
return {
|
||||||
name: section.addItemText,
|
name: SectionService.sectionsConfiguration[section]
|
||||||
link: `/${sectionId}/add`,
|
.addItemText,
|
||||||
|
link: `/${SectionService.sectionsConfiguration[section].sectionUrl}/add`,
|
||||||
};
|
};
|
||||||
}
|
}),
|
||||||
),
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Выйти",
|
name: "Выйти",
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ export abstract class HTTPService {
|
|||||||
schema: Z,
|
schema: Z,
|
||||||
options?: RequestOptions
|
options?: RequestOptions
|
||||||
) {
|
) {
|
||||||
console.log(options?.body);
|
|
||||||
return await fetch(process.env.NEXT_PUBLIC_BASE_URL + url, {
|
return await fetch(process.env.NEXT_PUBLIC_BASE_URL + url, {
|
||||||
method: method,
|
method: method,
|
||||||
headers: {
|
headers: {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import Link from "next/link";
|
|||||||
import { useSelectedLayoutSegment } from "next/navigation";
|
import { useSelectedLayoutSegment } from "next/navigation";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import { UserActivities } from "@/features/userActivities";
|
import { UserActivities } from "@/features/userActivities";
|
||||||
import { ItemSections, ItemService } from "@/entities/item";
|
import { SectionService } from "@/features/sections";
|
||||||
|
|
||||||
export const Header = () => {
|
export const Header = () => {
|
||||||
const currentPageName = useSelectedLayoutSegment();
|
const currentPageName = useSelectedLayoutSegment();
|
||||||
@@ -25,7 +25,7 @@ export const Header = () => {
|
|||||||
<Link href="/">.Torrent</Link>
|
<Link href="/">.Torrent</Link>
|
||||||
</h1>
|
</h1>
|
||||||
<div className="hidden text-2xl lp:block">
|
<div className="hidden text-2xl lp:block">
|
||||||
{ItemSections.map((section) => (
|
{SectionService.sections.map((section) => (
|
||||||
<Link
|
<Link
|
||||||
key={section}
|
key={section}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
@@ -34,7 +34,7 @@ export const Header = () => {
|
|||||||
)}
|
)}
|
||||||
href={"/" + section}
|
href={"/" + section}
|
||||||
>
|
>
|
||||||
{ItemService.itemSections[section].sectionName}
|
{SectionService.sectionsConfiguration[section].sectionName}
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { ItemSections, ItemService } from "@/entities/item";
|
import { SectionService } from "@/features/sections";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
@@ -32,13 +32,13 @@ export const MobileMenu = () => {
|
|||||||
)}
|
)}
|
||||||
onClick={() => changeMenuOpen(false)}
|
onClick={() => changeMenuOpen(false)}
|
||||||
>
|
>
|
||||||
{ItemSections.map((section) => (
|
{SectionService.sections.map((section) => (
|
||||||
<Link
|
<Link
|
||||||
key={section}
|
key={section}
|
||||||
className="text-xl py-2 cursor-pointer hover:underline"
|
className="text-xl py-2 cursor-pointer hover:underline"
|
||||||
href={"/" + section}
|
href={"/" + section}
|
||||||
>
|
>
|
||||||
{ItemService.itemSections[section].sectionName}
|
{SectionService.sectionsConfiguration[section].sectionName}
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import {
|
|||||||
ItemCardType,
|
ItemCardType,
|
||||||
ItemService,
|
ItemService,
|
||||||
} from "@/entities/item";
|
} from "@/entities/item";
|
||||||
|
import { SectionService } from "@/features/sections";
|
||||||
import { Img } from "@/shared/ui";
|
import { Img } from "@/shared/ui";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
|
|
||||||
@@ -12,7 +13,14 @@ export const ItemCard = ({ card }: { card: ItemCardType }) => {
|
|||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
className="group/itemcard cursor-pointer"
|
className="group/itemcard cursor-pointer"
|
||||||
href={"/" + ItemService.GetSectionUrlByItemType(card) + "/" + card.id}
|
href={
|
||||||
|
"/" +
|
||||||
|
SectionService.sectionsConfiguration[
|
||||||
|
SectionService.itemTypeToSection[card.type]
|
||||||
|
].sectionUrl +
|
||||||
|
"/" +
|
||||||
|
card.id
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{!!card.cover && (
|
{!!card.cover && (
|
||||||
<Img
|
<Img
|
||||||
@@ -44,15 +44,15 @@ export const ItemInfo = <T extends ItemType | ItemCreateType>({
|
|||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
setValue,
|
setValue,
|
||||||
|
setError,
|
||||||
watch,
|
watch,
|
||||||
reset,
|
reset,
|
||||||
formState: { dirtyFields, errors },
|
formState: { dirtyFields, errors },
|
||||||
} = useForm<ItemType | ItemCreateType>({
|
} = useForm<ItemType | ItemCreateType>({
|
||||||
// Unfortunately, react hook form does not accept generic type correctly
|
|
||||||
// useForm<T> causes an error when calling register(key) ->
|
|
||||||
// key is not assignable to parameter of type 'Path<T>'
|
|
||||||
defaultValues: init_item,
|
defaultValues: init_item,
|
||||||
resolver: zodResolver(ItemService.GetFormResolver(item)),
|
resolver: zodResolver(
|
||||||
|
ItemService.itemsConfiguration[item.type].formResolver
|
||||||
|
),
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -72,7 +72,6 @@ export const ItemInfo = <T extends ItemType | ItemCreateType>({
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!Object.keys(dirtyFields).length) return;
|
if (!Object.keys(dirtyFields).length) return;
|
||||||
if (JSON.stringify(watchedData) === JSON.stringify(formData)) return;
|
if (JSON.stringify(watchedData) === JSON.stringify(formData)) return;
|
||||||
console.log(dirtyFields);
|
|
||||||
changeFormData(watchedData as T);
|
changeFormData(watchedData as T);
|
||||||
if (savedTimeout) clearTimeout(savedTimeout);
|
if (savedTimeout) clearTimeout(savedTimeout);
|
||||||
changeSavedTimeout(
|
changeSavedTimeout(
|
||||||
@@ -83,14 +82,15 @@ export const ItemInfo = <T extends ItemType | ItemCreateType>({
|
|||||||
}, [watchedData]);
|
}, [watchedData]);
|
||||||
|
|
||||||
const onSubmit = async (formData: ItemCreateType) => {
|
const onSubmit = async (formData: ItemCreateType) => {
|
||||||
changeSavedTimeout(null);
|
|
||||||
console.log(formData);
|
|
||||||
const updatedItem = ItemService.isExistingItem(item)
|
const updatedItem = ItemService.isExistingItem(item)
|
||||||
? await ItemService.ChangeItem(item.id, formData)
|
? await ItemService.ChangeItem(item.id, formData)
|
||||||
: await ItemService.AddItem(formData);
|
: await ItemService.AddItem(formData);
|
||||||
|
changeSavedTimeout(null);
|
||||||
if (updatedItem) {
|
if (updatedItem) {
|
||||||
changeItem(updatedItem as T);
|
changeItem(updatedItem as T);
|
||||||
reset({}, { keepValues: true });
|
reset({}, { keepValues: true });
|
||||||
|
} else {
|
||||||
|
setError("root", { message: "Ошибка сервера" });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { ItemCreateType, ItemType } from "@/entities/item";
|
import { ItemCreateType, ItemType } from "@/entities/item";
|
||||||
import { ItemService } from "@/entities/item/item";
|
import { ItemService } from "@/entities/item/item";
|
||||||
|
import { ItemPropertiesDescriptionType } from "@/entities/item/types";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import { UseFormRegister, UseFormSetValue } from "react-hook-form";
|
import { UseFormRegister, UseFormSetValue } from "react-hook-form";
|
||||||
|
|
||||||
@@ -23,8 +24,10 @@ export const ItemProperties = <T extends ItemType | ItemCreateType>({
|
|||||||
!editable && "cursor-default"
|
!editable && "cursor-default"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{(ItemService.GetPropertiesDescriptionForItem(item) ?? []).map(
|
{(
|
||||||
(section, i) => (
|
ItemService.itemsConfiguration[item.type]
|
||||||
|
.propertiesDescription as ItemPropertiesDescriptionType<T>
|
||||||
|
).map((section, i) => (
|
||||||
<ul key={i} className="w-[48%] bg-bg1 rounded-lg py-1 px-4">
|
<ul key={i} className="w-[48%] bg-bg1 rounded-lg py-1 px-4">
|
||||||
{section.map((req) => (
|
{section.map((req) => (
|
||||||
<li key={req.name} className="text-sm lp:text-md py-1">
|
<li key={req.name} className="text-sm lp:text-md py-1">
|
||||||
@@ -77,8 +80,7 @@ export const ItemProperties = <T extends ItemType | ItemCreateType>({
|
|||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
)
|
))}
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import Link from "next/link";
|
|||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import Masonry, { ResponsiveMasonry } from "react-responsive-masonry";
|
import Masonry, { ResponsiveMasonry } from "react-responsive-masonry";
|
||||||
import { boolean } from "zod";
|
|
||||||
|
|
||||||
export const Section = ({
|
export const Section = ({
|
||||||
name,
|
name,
|
||||||
|
|||||||
Reference in New Issue
Block a user