edits
This commit is contained in:
gofnnp 2025-06-16 20:38:32 +04:00
parent b26161f7d5
commit 851bcc1d4f
39 changed files with 114 additions and 122 deletions

View File

@ -1,8 +1,7 @@
'use client'; 'use client';
import Button from '@/components/ui/Button/Button';
import Typography from '@/components/ui/Typography/Typography';
import { useEffect } from 'react'; import { useEffect } from 'react';
import { Button, Typography } from '@/components/ui';
import styles from "./error.module.scss" import styles from "./error.module.scss"
export default function Error({ export default function Error({

View File

@ -1,4 +1,4 @@
import NavigationBar from "@/components/NavigationBar/NavigationBar"; import { NavigationBar } from "@/components/layout";
import styles from "./layout.module.scss"; import styles from "./layout.module.scss";
export default function CoreLayout({ export default function CoreLayout({

View File

@ -1,4 +1,4 @@
import Spinner from "@/components/ui/Spinner/Spinner"; import { Spinner } from "@/components/ui";
import styles from "./loading.module.scss" import styles from "./loading.module.scss"
export default function Loading() { export default function Loading() {

View File

@ -1,11 +1,17 @@
import { Suspense } from "react"; import { Suspense } from "react";
import Horoscope from "@/components/Horoscope/Horoscope";
import styles from "./page.module.scss";
import AdvisersSection, { AdvisersSectionSkeleton } from "@/components/AdvisersSection/AdvisersSection";
import CompatibilitySection, { CompatibilitySectionSkeleton } from "@/components/CompatibilitySection/CompatibilitySection";
import MeditationSection, { MeditationSectionSkeleton } from "@/components/MeditationSection/MeditationSection";
import PalmSection, { PalmSectionSkeleton } from "@/components/PalmSection/PalmSection";
import { loadAssistants, loadCompatibility, loadMeditations, loadPalms } from "@/entities/dashboard/loaders"; import { loadAssistants, loadCompatibility, loadMeditations, loadPalms } from "@/entities/dashboard/loaders";
import { Horoscope } from "@/components/widgets";
import {
AdvisersSection,
AdvisersSectionSkeleton,
CompatibilitySection,
CompatibilitySectionSkeleton,
MeditationSection,
MeditationSectionSkeleton,
PalmSection,
PalmSectionSkeleton
} from "@/components/domains/dashboard";
import styles from "./page.module.scss";
export default function Home() { export default function Home() {
return ( return (

View File

@ -1,8 +1,8 @@
import type { Metadata } from "next"; import type { Metadata } from "next";
import { Inter } from "next/font/google"; import { Inter } from "next/font/google";
import clsx from "clsx"; import clsx from "clsx";
import styles from "./layout.module.scss"
import "@/styles/globals.css"; import "@/styles/globals.css";
import styles from "./layout.module.scss"
const inter = Inter({ const inter = Inter({
subsets: ["latin", "cyrillic"], subsets: ["latin", "cyrillic"],
@ -11,7 +11,7 @@ const inter = Inter({
}); });
export const metadata: Metadata = { export const metadata: Metadata = {
title: "Wit Apps | AURA", title: "WIT",
description: "More than 14M people have experienced the value of our products. Wit Apps, headquartered in Silicon Valley, California, is a tech company that constructs global enterprises specializing in mobile-first products. We believe in the transformative power of technology, capable of turning chaos into miracles, thus enhancing the lives of millions. To realize this vision, we integrate leading expertise in artificial intelligence with a deep understanding of consumer needs and lifestyle trends.", description: "More than 14M people have experienced the value of our products. Wit Apps, headquartered in Silicon Valley, California, is a tech company that constructs global enterprises specializing in mobile-first products. We believe in the transformative power of technology, capable of turning chaos into miracles, thus enhancing the lives of millions. To realize this vision, we integrate leading expertise in artificial intelligence with a deep understanding of consumer needs and lifestyle trends.",
}; };

View File

@ -1,5 +0,0 @@
import Typography from "../ui/Typography/Typography";
export default function Logo() {
return <Typography size="xl" weight="medium">AURA</Typography>
}

View File

@ -1,4 +1,4 @@
.card.adviserCard { .card.card {
padding: 0; padding: 0;
min-width: 160px; min-width: 160px;
height: 235px; height: 235px;

View File

@ -1,10 +1,6 @@
import clsx from "clsx"
import Button from "../ui/Button/Button"
import Card from "../ui/Card/Card"
import Typography from "../ui/Typography/Typography"
import styles from "./AdviserCard.module.scss"
import { Assistant } from "@/entities/dashboard/types" import { Assistant } from "@/entities/dashboard/types"
import Stars from "../ui/Stars/Stars" import { Button, Card, Stars, Typography } from "@/components/ui"
import styles from "./AdviserCard.module.scss"
type AdviserCardProps = Assistant; type AdviserCardProps = Assistant;
@ -16,7 +12,7 @@ export default function AdviserCard({
description description
}: AdviserCardProps) { }: AdviserCardProps) {
return ( return (
<Card className={clsx(styles.card, styles.adviserCard)} style={{ backgroundImage: `url(${photoUrl})` }}> <Card className={styles.card} style={{ backgroundImage: `url(${photoUrl})` }}>
<div className={styles.content}> <div className={styles.content}>
<div className={styles.info}> <div className={styles.info}>
<div className={styles.name}> <div className={styles.name}>

View File

@ -1,4 +1,4 @@
.card { .card.card {
padding: 0; padding: 0;
min-width: 320px; min-width: 320px;
height: 110px; height: 110px;

View File

@ -1,10 +1,8 @@
import Image from "next/image"; import Image from "next/image";
import Card from "../ui/Card/Card"
import Typography from "../ui/Typography/Typography"
import styles from "./CompatibilityCard.module.scss"
import { IconName } from "../ui/Icon/Icon";
import MetaLabel from "../ui/MetaLabel/MetaLabel";
import { CompatibilityAction } from "@/entities/dashboard/types"; import { CompatibilityAction } from "@/entities/dashboard/types";
import { Card, MetaLabel, Typography } from "@/components/ui";
import { IconName } from "@/components/ui/Icon/Icon";
import styles from "./CompatibilityCard.module.scss";
type CompatibilityCardProps = CompatibilityAction; type CompatibilityCardProps = CompatibilityAction;

View File

@ -1,4 +1,4 @@
.card { .card.card {
padding: 0; padding: 0;
min-width: 342px; min-width: 342px;
height: 308px; height: 308px;

View File

@ -1,11 +1,8 @@
import Image from "next/image"; import Image from "next/image";
import Card from "../ui/Card/Card"
import Typography from "../ui/Typography/Typography"
import styles from "./MeditationCard.module.scss"
import Icon, { IconName } from "../ui/Icon/Icon";
import MetaLabel from "../ui/MetaLabel/MetaLabel";
import Button from "../ui/Button/Button";
import { Meditation } from "@/entities/dashboard/types"; import { Meditation } from "@/entities/dashboard/types";
import { Button, Card, Icon, MetaLabel, Typography } from "@/components/ui";
import { IconName } from "@/components/ui/Icon/Icon";
import styles from "./MeditationCard.module.scss"
type MeditationCardProps = Meditation; type MeditationCardProps = Meditation;

View File

@ -1,4 +1,4 @@
.card { .card.card {
padding: 0; padding: 0;
min-width: 200px; min-width: 200px;
height: 227px; height: 227px;

View File

@ -1,10 +1,8 @@
import Image from "next/image"; import Image from "next/image";
import Card from "../ui/Card/Card"
import Typography from "../ui/Typography/Typography"
import styles from "./PalmCard.module.scss"
import { IconName } from "../ui/Icon/Icon";
import MetaLabel from "../ui/MetaLabel/MetaLabel";
import { PalmAction } from "@/entities/dashboard/types"; import { PalmAction } from "@/entities/dashboard/types";
import { Card, MetaLabel, Typography } from "@/components/ui";
import { IconName } from "@/components/ui/Icon/Icon";
import styles from "./PalmCard.module.scss";
type PalmCardProps = PalmAction; type PalmCardProps = PalmAction;

View File

@ -0,0 +1,4 @@
export { default as AdviserCard } from './AdviserCard/AdviserCard';
export { default as CompatibilityCard } from './CompatibilityCard/CompatibilityCard';
export { default as MeditationCard } from './MeditationCard/MeditationCard';
export { default as PalmCard } from './PalmCard/PalmCard';

View File

@ -0,0 +1,2 @@
export * from './cards';
export * from './sections';

View File

@ -1,16 +1,10 @@
.sectionContent { .sectionContent.sectionContent {
overflow-x: scroll; overflow-x: scroll;
width: calc(100% + 32px); width: calc(100% + 32px);
padding: 32px 16px; padding: 32px 16px;
padding-right: 0;
margin: -32px -16px; margin: -32px -16px;
margin-right: 0;
} }
.grid { .skeleton.skeleton {
padding-right: 16px;
}
.advisersSkeleton.skeleton {
height: 486px; height: 486px;
} }

View File

@ -1,11 +1,8 @@
import { Assistant } from "@/entities/dashboard/types"; import { Assistant } from "@/entities/dashboard/types";
import AdviserCard from "../AdviserCard/AdviserCard";
import Grid from "../ui/Grid/Grid"
import Section from "../ui/Section/Section"
import styles from "./AdvisersSection.module.scss"
import { use } from "react"; import { use } from "react";
import Skeleton from "../ui/Skeleton/Skeleton"; import { AdviserCard } from "../../cards";
import clsx from "clsx"; import { Grid, Section, Skeleton } from "@/components/ui";
import styles from "./AdvisersSection.module.scss";
export default function AdvisersSection({ promise }: { promise: Promise<Assistant[]> }) { export default function AdvisersSection({ promise }: { promise: Promise<Assistant[]> }) {
const assistants = use(promise); const assistants = use(promise);
@ -25,7 +22,7 @@ export default function AdvisersSection({ promise }: { promise: Promise<Assistan
export function AdvisersSectionSkeleton() { export function AdvisersSectionSkeleton() {
return ( return (
<Section title="Advisers" contentClassName={styles.sectionContent}> <Section title="Advisers" contentClassName={styles.sectionContent}>
<Skeleton className={clsx(styles.advisersSkeleton, styles.skeleton)} /> <Skeleton className={styles.skeleton} />
</Section> </Section>
) )
} }

View File

@ -1,14 +1,10 @@
.sectionContent { .sectionContent.sectionContent {
overflow-x: scroll; overflow-x: scroll;
width: calc(100% + 32px); width: calc(100% + 32px);
padding: 16px; padding: 16px;
margin: -16px; margin: -16px;
} }
.grid { .skeleton.skeleton {
padding-right: 16px;
}
.compatibilitySkeleton.skeleton {
height: 236px; height: 236px;
} }

View File

@ -1,11 +1,8 @@
import { CompatibilityAction } from "@/entities/dashboard/types"; import { CompatibilityAction } from "@/entities/dashboard/types";
import CompatibilityCard from "../CompatibilityCard/CompatibilityCard";
import Grid from "../ui/Grid/Grid"
import Section from "../ui/Section/Section"
import styles from "./CompatibilitySection.module.scss"
import { use } from "react"; import { use } from "react";
import Skeleton from "../ui/Skeleton/Skeleton"; import { Grid, Section, Skeleton } from "@/components/ui";
import clsx from "clsx"; import { CompatibilityCard } from "../../cards";
import styles from "./CompatibilitySection.module.scss";
export default function CompatibilitySection({ promise }: { promise: Promise<CompatibilityAction[]> }) { export default function CompatibilitySection({ promise }: { promise: Promise<CompatibilityAction[]> }) {
const compatibilities = use(promise); const compatibilities = use(promise);
@ -25,7 +22,7 @@ export default function CompatibilitySection({ promise }: { promise: Promise<Com
export function CompatibilitySectionSkeleton() { export function CompatibilitySectionSkeleton() {
return ( return (
<Section title="Compatibility" contentClassName={styles.sectionContent}> <Section title="Compatibility" contentClassName={styles.sectionContent}>
<Skeleton className={clsx(styles.compatibilitySkeleton, styles.skeleton)} /> <Skeleton className={styles.skeleton} />
</Section> </Section>
) )
} }

View File

@ -1,14 +1,10 @@
.sectionContent { .sectionContent.sectionContent {
overflow-x: scroll; overflow-x: scroll;
width: calc(100% + 32px); width: calc(100% + 32px);
padding: 16px; padding: 16px;
margin: -16px; margin: -16px;
} }
.grid { .skeleton.skeleton {
padding-right: 16px;
}
.meditationSkeleton.skeleton {
height: 308px; height: 308px;
} }

View File

@ -1,11 +1,8 @@
import { Meditation } from "@/entities/dashboard/types"; import { Meditation } from "@/entities/dashboard/types";
import MeditationCard from "../MeditationCard/MeditationCard";
import Grid from "../ui/Grid/Grid"
import Section from "../ui/Section/Section"
import styles from "./MeditationSection.module.scss"
import { use } from "react"; import { use } from "react";
import Skeleton from "../ui/Skeleton/Skeleton"; import { Grid, Section, Skeleton } from "@/components/ui";
import clsx from "clsx"; import { MeditationCard } from "../../cards";
import styles from "./MeditationSection.module.scss";
export default function MeditationSection({ promise }: { promise: Promise<Meditation[]> }) { export default function MeditationSection({ promise }: { promise: Promise<Meditation[]> }) {
const meditations = use(promise); const meditations = use(promise);
@ -25,7 +22,7 @@ export default function MeditationSection({ promise }: { promise: Promise<Medita
export function MeditationSectionSkeleton() { export function MeditationSectionSkeleton() {
return ( return (
<Section title="Meditations" contentClassName={styles.sectionContent}> <Section title="Meditations" contentClassName={styles.sectionContent}>
<Skeleton className={clsx(styles.meditationSkeleton, styles.skeleton)} /> <Skeleton className={styles.skeleton} />
</Section> </Section>
) )
} }

View File

@ -1,14 +1,10 @@
.sectionContent { .sectionContent.sectionContent {
overflow-x: scroll; overflow-x: scroll;
width: calc(100% + 32px); width: calc(100% + 32px);
padding: 16px; padding: 16px;
margin: -16px; margin: -16px;
} }
.grid { .skeleton.skeleton {
padding-right: 16px;
}
.palmSkeleton.skeleton {
height: 227px; height: 227px;
} }

View File

@ -1,11 +1,8 @@
import { PalmAction } from "@/entities/dashboard/types"; import { PalmAction } from "@/entities/dashboard/types";
import PalmCard from "../PalmCard/PalmCard";
import Grid from "../ui/Grid/Grid"
import Section from "../ui/Section/Section"
import styles from "./PalmSection.module.scss"
import { use } from "react"; import { use } from "react";
import Skeleton from "../ui/Skeleton/Skeleton"; import { Grid, Section, Skeleton } from "@/components/ui";
import clsx from "clsx"; import { PalmCard } from "../../cards";
import styles from "./PalmSection.module.scss";
export default function PalmSection({ promise }: { promise: Promise<PalmAction[]> }) { export default function PalmSection({ promise }: { promise: Promise<PalmAction[]> }) {
const palms = use(promise); const palms = use(promise);
@ -25,7 +22,7 @@ export default function PalmSection({ promise }: { promise: Promise<PalmAction[]
export function PalmSectionSkeleton() { export function PalmSectionSkeleton() {
return ( return (
<Section title="Palm" contentClassName={styles.sectionContent}> <Section title="Palm" contentClassName={styles.sectionContent}>
<Skeleton className={clsx(styles.palmSkeleton, styles.skeleton)} /> <Skeleton className={styles.skeleton} />
</Section> </Section>
) )
} }

View File

@ -0,0 +1,4 @@
export { default as AdvisersSection, AdvisersSectionSkeleton } from './AdvisersSection/AdvisersSection';
export { default as CompatibilitySection, CompatibilitySectionSkeleton } from './CompatibilitySection/CompatibilitySection';
export { default as MeditationSection, MeditationSectionSkeleton } from './MeditationSection/MeditationSection';
export { default as PalmSection, PalmSectionSkeleton } from './PalmSection/PalmSection';

View File

@ -0,0 +1,5 @@
import { Typography } from "@/components/ui";
export default function Logo() {
return <Typography size="xl" weight="medium">WIT</Typography>
}

View File

@ -1,7 +1,8 @@
import Logo from "../Logo/Logo" import { Icon } from "@/components/ui";
import Icon, { IconName } from "../ui/Icon/Icon"
import styles from "./NavigationBar.module.scss"
import clsx from "clsx"; import clsx from "clsx";
import Logo from "../Logo/Logo";
import { IconName } from "@/components/ui/Icon/Icon";
import styles from "./NavigationBar.module.scss";
interface NavigationBarProps { interface NavigationBarProps {
className?: string; className?: string;

View File

@ -0,0 +1,2 @@
export { default as Logo } from './Logo/Logo';
export { default as NavigationBar } from './NavigationBar/NavigationBar';

View File

@ -1,7 +1,7 @@
import { ReactNode } from "react"; import { ReactNode } from "react";
import styles from "./MetaLabel.module.scss";
import IconLabel, { IconLabelProps } from "../IconLabel/IconLabel"; import IconLabel, { IconLabelProps } from "../IconLabel/IconLabel";
import Typography from "../Typography/Typography"; import Typography from "../Typography/Typography";
import styles from "./MetaLabel.module.scss";
export type MetaLabelProps = { export type MetaLabelProps = {
iconLabelProps: IconLabelProps; iconLabelProps: IconLabelProps;

View File

@ -1,7 +1,7 @@
import { ReactNode } from "react"; import { ReactNode } from "react";
import clsx from "clsx"; import clsx from "clsx";
import styles from "./Section.module.scss";
import Typography from "../Typography/Typography"; import Typography from "../Typography/Typography";
import styles from "./Section.module.scss";
interface SectionProps { interface SectionProps {
title?: string; title?: string;

View File

@ -1,6 +1,6 @@
import clsx from "clsx"; import clsx from "clsx";
import styles from "./styles.module.scss";
import { CSSProperties } from "react"; import { CSSProperties } from "react";
import styles from "./styles.module.scss";
export interface SpinnerProps { export interface SpinnerProps {
size?: number | string; size?: number | string;

View File

@ -1,6 +1,6 @@
import clsx from "clsx"; import clsx from "clsx";
import styles from "./TabBar.module.scss";
import Typography from "../Typography/Typography"; import Typography from "../Typography/Typography";
import styles from "./TabBar.module.scss";
export type Tab<T extends string> = { export type Tab<T extends string> = {
label: string; label: string;

View File

@ -0,0 +1,12 @@
export { default as Button } from './Button/Button';
export { default as Card } from './Card/Card';
export { default as Grid } from './Grid/Grid';
export { default as Icon } from './Icon/Icon';
export { default as IconLabel } from './IconLabel/IconLabel';
export { default as MetaLabel } from './MetaLabel/MetaLabel';
export { default as Section } from './Section/Section';
export { default as Skeleton } from './Skeleton/Skeleton';
export { default as Spinner } from './Spinner/Spinner';
export { default as Stars } from './Stars/Stars';
export { default as TabBar } from './TabBar/TabBar';
export { default as Typography } from './Typography/Typography';

View File

@ -12,7 +12,7 @@
color: #2A74DD; color: #2A74DD;
} }
.card { .card.card {
padding: 16px 0px; padding: 16px 0px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;

View File

@ -1,11 +1,9 @@
"use client"; "use client";
import { useMemo, useState } from "react"; import { useMemo, useState } from "react";
import TabBar, { Tab } from "../ui/TabBar/TabBar"; import { Button, Card, TabBar, Typography } from "@/components/ui";
import Text from "../ui/Typography/Typography"; import { Tab } from "@/components/ui/TabBar/TabBar";
import styles from "./Horoscope.module.scss"; import styles from "./Horoscope.module.scss";
import Card from "../ui/Card/Card";
import Button from "../ui/Button/Button";
type Period = "today" | "week" | "month" | "year"; type Period = "today" | "week" | "month" | "year";
@ -40,16 +38,16 @@ export default function Horoscope() {
<Card className={styles.card}> <Card className={styles.card}>
<TabBar<Period> tabs={TABS} active={active} onChange={setActive} /> <TabBar<Period> tabs={TABS} active={active} onChange={setActive} />
<div className={styles.content}> <div className={styles.content}>
<Text as="h3" weight="regular" className={styles.title}> <Typography as="h3" weight="regular" className={styles.title}>
Your Horoscope today Your Horoscope today
</Text> </Typography>
<Text as="p" weight="medium" className={styles.text}> <Typography as="p" weight="medium" className={styles.text}>
{text} {text}
</Text> </Typography>
{enableCollapse && <Button className={styles.seeAllButton} onClick={() => setIscollapsed((prev) => !prev)}> {enableCollapse && <Button className={styles.seeAllButton} onClick={() => setIscollapsed((prev) => !prev)}>
<Text as="span" size="sm" weight="medium" color="secondary" align="right"> <Typography as="span" size="sm" weight="medium" color="secondary" align="right">
{isCollapsed ? "See All" : "Hide"} {isCollapsed ? "See All" : "Hide"}
</Text> </Typography>
</Button>} </Button>}
</div> </div>
</Card> </Card>

View File

@ -0,0 +1 @@
export { default as Horoscope } from './Horoscope/Horoscope';

View File

@ -1,12 +1,9 @@
import { http } from "@/shared/api/httpClient"; import { http } from "@/shared/api/httpClient";
import { DashboardSchema, DashboardData } from "./types"; import { DashboardSchema, DashboardData } from "./types";
import { delay } from "@/shared/utils/delay";
export const getDashboard = async () => { export const getDashboard = async () => {
await delay(3_000);
return http.get<DashboardData>("/dashboard", { return http.get<DashboardData>("/dashboard", {
tags: ["dashboard"], tags: ["dashboard"],
schema: DashboardSchema, schema: DashboardSchema
}); });
} }

View File

@ -15,6 +15,7 @@ type RequestOpts = Omit<RequestInit, "method" | "body"> & {
tags?: string[]; // next.js cache-tag tags?: string[]; // next.js cache-tag
query?: Record<string, unknown>; // query-string query?: Record<string, unknown>; // query-string
schema?: z.ZodTypeAny; // runtime validation schema?: z.ZodTypeAny; // runtime validation
revalidate?: number;
}; };
class HttpClient { class HttpClient {
@ -35,12 +36,18 @@ class HttpClient {
opts: RequestOpts = {}, opts: RequestOpts = {},
body?: unknown body?: unknown
): Promise<T> { ): Promise<T> {
const { tags = [], schema, query, ...rest } = opts; const {
tags = [],
schema,
query,
revalidate = 300,
...rest
} = opts;
const res = await fetch(this.buildUrl(path, query), { const res = await fetch(this.buildUrl(path, query), {
method, method,
body: body ? JSON.stringify(body) : undefined, body: body ? JSON.stringify(body) : undefined,
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
next: { revalidate: 3600, tags }, next: { revalidate, tags },
...rest, ...rest,
}); });