diff --git a/.prettierignore b/.prettierignore
new file mode 100644
index 0000000..72fee2c
--- /dev/null
+++ b/.prettierignore
@@ -0,0 +1,8 @@
+# Ignore artifacts:
+build
+.next/
+dist
+node_modules/
+
+# Ignore files:
+package-lock.json
\ No newline at end of file
diff --git a/.prettierrc.json b/.prettierrc.json
new file mode 100644
index 0000000..4845cc5
--- /dev/null
+++ b/.prettierrc.json
@@ -0,0 +1,7 @@
+{
+ "semi": true,
+ "tabWidth": 2,
+ "printWidth": 100,
+ "singleQuote": true,
+ "trailingComma": "es5"
+}
\ No newline at end of file
diff --git a/next.config.ts b/next.config.ts
index e9ffa30..b9bd58d 100644
--- a/next.config.ts
+++ b/next.config.ts
@@ -1,7 +1,18 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
- /* config options here */
+ env: {
+ NEXT_PUBLIC_API_URL: process.env.NEXT_PUBLIC_API_URL,
+ },
+ images: {
+ remotePatterns: [
+ {
+ protocol: "https",
+ hostname: "aura-node.s3.eu-west-2.amazonaws.com",
+ pathname: "/**",
+ },
+ ],
+ },
};
export default nextConfig;
diff --git a/package-lock.json b/package-lock.json
index e218724..0ba87e1 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -21,6 +21,7 @@
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "15.3.3",
+ "prettier": "^3.5.3",
"typescript": "^5"
}
},
@@ -4626,6 +4627,22 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/prettier": {
+ "version": "3.5.3",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz",
+ "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
diff --git a/package.json b/package.json
index b5bcb52..685c71c 100644
--- a/package.json
+++ b/package.json
@@ -13,7 +13,8 @@
"next": "15.3.3",
"react": "^19.0.0",
"react-dom": "^19.0.0",
- "sass": "^1.89.2"
+ "sass": "^1.89.2",
+ "zod": "^3.25.64"
},
"devDependencies": {
"@eslint/eslintrc": "^3",
@@ -22,6 +23,7 @@
"@types/react-dom": "^19",
"eslint": "^9",
"eslint-config-next": "15.3.3",
+ "prettier": "^3.5.3",
"typescript": "^5"
}
}
diff --git a/src/app/(core)/error.module.scss b/src/app/(core)/error.module.scss
new file mode 100644
index 0000000..0351b6d
--- /dev/null
+++ b/src/app/(core)/error.module.scss
@@ -0,0 +1,6 @@
+.coreError {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 16px;
+}
\ No newline at end of file
diff --git a/src/app/(core)/error.tsx b/src/app/(core)/error.tsx
new file mode 100644
index 0000000..22f0b06
--- /dev/null
+++ b/src/app/(core)/error.tsx
@@ -0,0 +1,32 @@
+'use client';
+
+import Button from '@/components/ui/Button/Button';
+import Typography from '@/components/ui/Typography/Typography';
+import { useEffect } from 'react';
+import styles from "./error.module.scss"
+
+export default function Error({
+ error,
+ reset,
+}: {
+ error: Error & { digest?: string };
+ reset: () => void;
+}) {
+ useEffect(() => {
+ console.error(error);
+ }, [error]);
+
+ return (
+
+ Something went wrong!
+ {error.message}
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/app/(core)/loading.module.scss b/src/app/(core)/loading.module.scss
new file mode 100644
index 0000000..6c0ba2e
--- /dev/null
+++ b/src/app/(core)/loading.module.scss
@@ -0,0 +1,5 @@
+.coreSpinnerContainer {
+ width: 100%;
+ display: flex;
+ justify-content: center;
+}
\ No newline at end of file
diff --git a/src/app/(core)/loading.tsx b/src/app/(core)/loading.tsx
new file mode 100644
index 0000000..902aa8f
--- /dev/null
+++ b/src/app/(core)/loading.tsx
@@ -0,0 +1,10 @@
+import Spinner from "@/components/ui/Spinner/Spinner";
+import styles from "./loading.module.scss"
+
+export default function Loading() {
+ return (
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/src/app/(core)/page.tsx b/src/app/(core)/page.tsx
index ce53bf6..7b3cb88 100644
--- a/src/app/(core)/page.tsx
+++ b/src/app/(core)/page.tsx
@@ -1,16 +1,32 @@
+import { Suspense } from "react";
import Horoscope from "@/components/Horoscope/Horoscope";
-import styles from "./page.module.scss"
-import AdvisersSection from "@/components/AdvisersSection/AdvisersSection";
-import CompatibilitySection from "@/components/CompatibilitySection/CompatibilitySection";
-import MeditationSection from "@/components/MeditationSection/MeditationSection";
-import PalmSection from "@/components/PalmSection/PalmSection";
+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";
export default function Home() {
- return ;
+ return (
+
+
+
+ }>
+
+
+
+ }>
+
+
+
+ }>
+
+
+
+ }>
+
+
+
+ );
}
\ No newline at end of file
diff --git a/src/components/AdviserCard/AdviserCard.module.scss b/src/components/AdviserCard/AdviserCard.module.scss
index 638be48..d2dba98 100644
--- a/src/components/AdviserCard/AdviserCard.module.scss
+++ b/src/components/AdviserCard/AdviserCard.module.scss
@@ -8,6 +8,8 @@
position: relative;
overflow: hidden;
background-repeat: no-repeat;
+ background-size: cover;
+ background-position: center;
}
.content {
@@ -46,12 +48,6 @@
display: flex;
align-items: center;
gap: 4px;
-
- &>.stars {
- display: flex;
- align-items: center;
- gap: 3px;
- }
}
}
}
diff --git a/src/components/AdviserCard/AdviserCard.tsx b/src/components/AdviserCard/AdviserCard.tsx
index 0aa3ae1..0b03367 100644
--- a/src/components/AdviserCard/AdviserCard.tsx
+++ b/src/components/AdviserCard/AdviserCard.tsx
@@ -3,44 +3,38 @@ 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 Stars from "../ui/Stars/Stars"
-export default function AdviserCard() {
+type AdviserCardProps = Assistant;
+
+export default function AdviserCard({
+ name,
+ photoUrl,
+ rating,
+ reviewCount,
+ description
+}: AdviserCardProps) {
return (
-
+
- Astrologer - 7 years
+ {description}
- 4.8
+ {rating}
-
-
-
-
-
-
-
+
- (5762)
+ ({reviewCount})
diff --git a/src/components/AdvisersSection/AdvisersSection.module.scss b/src/components/AdvisersSection/AdvisersSection.module.scss
index 3b4a558..3b7415d 100644
--- a/src/components/AdvisersSection/AdvisersSection.module.scss
+++ b/src/components/AdvisersSection/AdvisersSection.module.scss
@@ -9,4 +9,8 @@
.grid {
padding-right: 16px;
+}
+
+.advisersSkeleton.skeleton {
+ height: 486px;
}
\ No newline at end of file
diff --git a/src/components/AdvisersSection/AdvisersSection.tsx b/src/components/AdvisersSection/AdvisersSection.tsx
index 321778c..f5f2a0e 100644
--- a/src/components/AdvisersSection/AdvisersSection.tsx
+++ b/src/components/AdvisersSection/AdvisersSection.tsx
@@ -1,29 +1,31 @@
+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 Skeleton from "../ui/Skeleton/Skeleton";
+import clsx from "clsx";
-const advisers = [
- { name: "Marta", img: "/marta.jpg", rating: 4.8, years: 7 },
- { name: "Marta", img: "/marta.jpg", rating: 4.8, years: 7 },
- { name: "Marta", img: "/marta.jpg", rating: 4.8, years: 7 },
- { name: "Marta", img: "/marta.jpg", rating: 4.8, years: 7 },
- { name: "Marta", img: "/marta.jpg", rating: 4.8, years: 7 },
- { name: "Marta", img: "/marta.jpg", rating: 4.8, years: 7 },
- { name: "Marta", img: "/marta.jpg", rating: 4.8, years: 7 },
- { name: "Marta", img: "/marta.jpg", rating: 4.8, years: 7 },
- { name: "Marta", img: "/marta.jpg", rating: 4.8, years: 7 },
- { name: "Marta", img: "/marta.jpg", rating: 4.8, years: 7 },
-];
+export default function AdvisersSection({ promise }: { promise: Promise
}) {
+ const assistants = use(promise);
+ const columns = Math.ceil(assistants?.length / 2);
-export default function AdvisersSection() {
return (
-
- {advisers.map((adviser, index) => (
-
+
+ {assistants.map((adviser) => (
+
))}
)
+}
+
+export function AdvisersSectionSkeleton() {
+ return (
+
+ )
}
\ No newline at end of file
diff --git a/src/components/CompatibilityCard/CompatibilityCard.module.scss b/src/components/CompatibilityCard/CompatibilityCard.module.scss
index 5cf1a49..925e259 100644
--- a/src/components/CompatibilityCard/CompatibilityCard.module.scss
+++ b/src/components/CompatibilityCard/CompatibilityCard.module.scss
@@ -13,4 +13,9 @@
display: flex;
flex-direction: column;
justify-content: space-between;
+}
+
+.compatibilityImage {
+ object-fit: cover;
+ object-position: center;
}
\ No newline at end of file
diff --git a/src/components/CompatibilityCard/CompatibilityCard.tsx b/src/components/CompatibilityCard/CompatibilityCard.tsx
index 8abdfec..1144797 100644
--- a/src/components/CompatibilityCard/CompatibilityCard.tsx
+++ b/src/components/CompatibilityCard/CompatibilityCard.tsx
@@ -4,28 +4,36 @@ 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";
-export default function CompatibilityCard() {
+type CompatibilityCardProps = CompatibilityAction;
+
+export default function CompatibilityCard({
+ imageUrl,
+ title,
+ type,
+ minutes
+}: CompatibilityCardProps) {
return (
-
- Compatibility
+
+ {title}
Article
+ children: {type}
}}>
- 5 min
+ {minutes} min
diff --git a/src/components/CompatibilitySection/CompatibilitySection.module.scss b/src/components/CompatibilitySection/CompatibilitySection.module.scss
index 15f758e..8d37ec7 100644
--- a/src/components/CompatibilitySection/CompatibilitySection.module.scss
+++ b/src/components/CompatibilitySection/CompatibilitySection.module.scss
@@ -7,4 +7,8 @@
.grid {
padding-right: 16px;
+}
+
+.compatibilitySkeleton.skeleton {
+ height: 236px;
}
\ No newline at end of file
diff --git a/src/components/CompatibilitySection/CompatibilitySection.tsx b/src/components/CompatibilitySection/CompatibilitySection.tsx
index 64b57fa..82ecdfc 100644
--- a/src/components/CompatibilitySection/CompatibilitySection.tsx
+++ b/src/components/CompatibilitySection/CompatibilitySection.tsx
@@ -1,29 +1,31 @@
+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 Skeleton from "../ui/Skeleton/Skeleton";
+import clsx from "clsx";
-const compatibilities = [
- { title: "Compatibility" },
- { title: "Compatibility" },
- { title: "Compatibility" },
- { title: "Compatibility" },
- { title: "Compatibility" },
- { title: "Compatibility" },
- { title: "Compatibility" },
- { title: "Compatibility" },
- { title: "Compatibility" },
- { title: "Compatibility" },
-];
+export default function CompatibilitySection({ promise }: { promise: Promise }) {
+ const compatibilities = use(promise);
+ const columns = Math.ceil(compatibilities?.length / 2);
-export default function CompatibilitySection() {
return (
-
- {compatibilities.map((compatibility, index) => (
-
+
+ {compatibilities.map((compatibility) => (
+
))}
)
+}
+
+export function CompatibilitySectionSkeleton() {
+ return (
+
+ )
}
\ No newline at end of file
diff --git a/src/components/MeditationCard/MeditationCard.module.scss b/src/components/MeditationCard/MeditationCard.module.scss
index 15d5d07..82a7838 100644
--- a/src/components/MeditationCard/MeditationCard.module.scss
+++ b/src/components/MeditationCard/MeditationCard.module.scss
@@ -33,4 +33,9 @@
transform: rotate(180deg);
}
}
+}
+
+.meditationImage {
+ object-fit: cover;
+ object-position: center;
}
\ No newline at end of file
diff --git a/src/components/MeditationCard/MeditationCard.tsx b/src/components/MeditationCard/MeditationCard.tsx
index 6edbf2a..8db2cc5 100644
--- a/src/components/MeditationCard/MeditationCard.tsx
+++ b/src/components/MeditationCard/MeditationCard.tsx
@@ -5,13 +5,21 @@ 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";
-export default function MeditationCard() {
+type MeditationCardProps = Meditation;
+
+export default function MeditationCard({
+ imageUrl,
+ title,
+ type,
+ minutes
+}: MeditationCardProps) {
return (
- Reset
+ {title}
Therapy
+ children: {type}
}}>
- 15 min
+ {minutes} min