build improvements
This commit is contained in:
parent
4d239f7c7a
commit
5c3fe39074
@ -26,6 +26,11 @@ services:
|
|||||||
ports:
|
ports:
|
||||||
- "4012:5432"
|
- "4012:5432"
|
||||||
|
|
||||||
|
yogamail:
|
||||||
|
image: dockage/mailcatcher:0.9.0
|
||||||
|
ports:
|
||||||
|
- "4013:1080"
|
||||||
|
- "4014:1025"
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
next-db: {}
|
next-db: {}
|
||||||
|
|||||||
@ -1 +1 @@
|
|||||||
202501081712.9d7bb39
|
202502042213.4d239f7
|
||||||
|
|||||||
@ -9,4 +9,4 @@ echo "build image ${TAG} from folder ${PROJECT_ROOT}"
|
|||||||
|
|
||||||
cd $PROJECT_ROOT
|
cd $PROJECT_ROOT
|
||||||
|
|
||||||
docker build --platform linux/amd64 -t $TAG .
|
docker build -t $TAG .
|
||||||
|
|||||||
@ -1,4 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
ENV_DEV_DIR=$(readlink -f "${CURRENT_DIR}/../../../environments/dev/docker-compose")
|
|
||||||
COMPOSE_FILE=$(readlink -f "/docker-compose.yml")
|
|
||||||
@ -1,8 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
CURRENT_DIR=$(dirname "$0")
|
|
||||||
source "${CURRENT_DIR}/start.docker.compose.env.sh"
|
|
||||||
|
|
||||||
cd "${ENV_DEV_DIR}"
|
|
||||||
echo "starting compose file in ${ENV_DEV_DIR}"
|
|
||||||
docker compose up -d
|
|
||||||
@ -1,18 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
CURRENT_DIR=$(dirname "$0")
|
|
||||||
source "${CURRENT_DIR}/build.docker.env.sh"
|
|
||||||
source "${CURRENT_DIR}/start.docker.compose.env.sh"
|
|
||||||
echo "updating image version to ${VERSION} in compose file ${COMPOSE_FILE}"
|
|
||||||
#export TAG=docker.rschneider.hu/infra/yogastic:$VERSION
|
|
||||||
|
|
||||||
case $(uname) in
|
|
||||||
"Darwin")
|
|
||||||
echo "Detected macOS"
|
|
||||||
sed -i'' -e "s/docker.rschneider.hu\\/infra\\/yogastic:.*/docker.rschneider.hu\\/infra\\/yogastic:$VERSION/g" $COMPOSE_FILE
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
sed -i "s/docker.rschneider.hu\\/infra\\/yogastic:.*/docker.rschneider.hu\\/infra\\/yogastic:$VERSION/g" $COMPOSE_FILE
|
|
||||||
#sed -i "s/docker.rschneider.hu\\/infra\\/yogastic:.*/docker.rschneider.hu\\/infra\\/yogastic:$VERSION/g" $COMPOSE_FILE
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
|
|
||||||
CURRENT_DIR=$(dirname "$0")
|
|
||||||
source "${CURRENT_DIR}/build.docker.env.sh"
|
|
||||||
source "${CURRENT_DIR}/start.docker.compose.env.sh"
|
|
||||||
|
|
||||||
cd ${ENV_DEV_DIR}
|
|
||||||
echo "Destroy compose in ${ENV_DEV_DIR}"
|
|
||||||
docker compose down -v
|
|
||||||
@ -1,10 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
|
|
||||||
CURRENT_DIR=$(dirname "$0")
|
|
||||||
source "${CURRENT_DIR}/build.docker.env.sh"
|
|
||||||
source "${CURRENT_DIR}/start.docker.compose.env.sh"
|
|
||||||
|
|
||||||
cd ${ENV_DEV_DIR}
|
|
||||||
echo "Stopping compose in ${ENV_DEV_DIR}"
|
|
||||||
docker compose down
|
|
||||||
@ -1 +1 @@
|
|||||||
202501071722.a8b144f
|
202502042213.4d239f7
|
||||||
|
|||||||
49
environment/infra/jenkins/build.cms.image.Jenkinsfile
Normal file
49
environment/infra/jenkins/build.cms.image.Jenkinsfile
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
pipeline {
|
||||||
|
agent any
|
||||||
|
|
||||||
|
environment {
|
||||||
|
DOCKER_IMAGE = 'yoga-cms'
|
||||||
|
DOCKER_REGISTRY = 'your-docker-registry'
|
||||||
|
DOCKER_CREDENTIALS_ID = 'your-docker-credentials-id'
|
||||||
|
}
|
||||||
|
|
||||||
|
stages {
|
||||||
|
stage('Checkout') {
|
||||||
|
steps {
|
||||||
|
checkout([$class: 'GitSCM', branches: [[name: '*/main']], userRemoteConfigs: [[url: 'https://gitea.rschneider.hu/rschneider/yogastic.git', credentialsId: 'rschneider_gitea.rschneider.hu']]])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Build Docker Image') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
// docker.build("${DOCKER_IMAGE}:${env.BUILD_ID}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Push Docker Image') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
// docker.withRegistry("https://${DOCKER_REGISTRY}", DOCKER_CREDENTIALS_ID) {
|
||||||
|
// docker.image("${DOCKER_IMAGE}:${env.BUILD_ID}").push()
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Cleanup') {
|
||||||
|
steps {
|
||||||
|
script {
|
||||||
|
docker.image("${DOCKER_IMAGE}:${env.BUILD_ID}").remove()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
post {
|
||||||
|
always {
|
||||||
|
cleanWs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -21,4 +21,5 @@ echo $CMD1
|
|||||||
echo $CMD2
|
echo $CMD2
|
||||||
${CMD1}
|
${CMD1}
|
||||||
${CMD2}
|
${CMD2}
|
||||||
|
|
||||||
echo "done"
|
echo "done"
|
||||||
|
|||||||
@ -10,7 +10,28 @@ const compat = new FlatCompat({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const eslintConfig = [
|
const eslintConfig = [
|
||||||
...compat.extends("next/core-web-vitals", "next/typescript"),
|
...compat.config(
|
||||||
|
{
|
||||||
|
extends:[
|
||||||
|
"next/core-web-vitals",
|
||||||
|
"next/typescript",
|
||||||
|
],
|
||||||
|
// rules: {
|
||||||
|
// "@typescript-eslint/no-explicit-any": "off"
|
||||||
|
// },
|
||||||
|
}
|
||||||
|
|
||||||
|
),
|
||||||
|
|
||||||
|
// {
|
||||||
|
// name: "custom",
|
||||||
|
// "files": ["src/types/generated-strapi-interfaces/api/article.ts"], // Or *.test.js
|
||||||
|
// rules: {
|
||||||
|
// "@typescript-eslint/no-explicit-any": "off"
|
||||||
|
// },
|
||||||
|
// }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
console.info("eslint config",eslintConfig)
|
||||||
|
|
||||||
export default eslintConfig;
|
export default eslintConfig;
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import type { NextConfig } from "next";
|
|||||||
const nextConfig: NextConfig = {
|
const nextConfig: NextConfig = {
|
||||||
/* config options here */
|
/* config options here */
|
||||||
output: "standalone",
|
output: "standalone",
|
||||||
|
|
||||||
sassOptions: {
|
sassOptions: {
|
||||||
silenceDeprecations: [
|
silenceDeprecations: [
|
||||||
'abs-percent',
|
'abs-percent',
|
||||||
|
|||||||
1310
yoga-app/package-lock.json
generated
1310
yoga-app/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -11,6 +11,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-free": "^6.7.2",
|
"@fortawesome/fontawesome-free": "^6.7.2",
|
||||||
|
"@strapi/database": "^5.10.3",
|
||||||
"@types/aos": "^3.0.7",
|
"@types/aos": "^3.0.7",
|
||||||
"@types/bcrypt": "^5.0.2",
|
"@types/bcrypt": "^5.0.2",
|
||||||
"@types/bcryptjs": "^2.4.6",
|
"@types/bcryptjs": "^2.4.6",
|
||||||
@ -18,6 +19,9 @@
|
|||||||
"@types/ityped": "^1.0.3",
|
"@types/ityped": "^1.0.3",
|
||||||
"@types/pg": "^8.11.10",
|
"@types/pg": "^8.11.10",
|
||||||
"@types/qs": "^6.9.18",
|
"@types/qs": "^6.9.18",
|
||||||
|
"ajv": "^8.17.1",
|
||||||
|
"ajv-formats": "^3.0.1",
|
||||||
|
"ajv-i18n": "^4.2.0",
|
||||||
"aos": "^2.3.4",
|
"aos": "^2.3.4",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"bootstrap": "^4.6.2",
|
"bootstrap": "^4.6.2",
|
||||||
@ -25,16 +29,19 @@
|
|||||||
"dotenv": "^16.4.7",
|
"dotenv": "^16.4.7",
|
||||||
"ityped": "^1.0.3",
|
"ityped": "^1.0.3",
|
||||||
"next": "15.1.3",
|
"next": "15.1.3",
|
||||||
|
"nodemailer": "^6.10.0",
|
||||||
"pg": "^8.13.1",
|
"pg": "^8.13.1",
|
||||||
"qs": "^6.14.0",
|
"qs": "^6.14.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-bootstrap": "^2.10.9",
|
"react-bootstrap": "^2.10.9",
|
||||||
"react-dom": "^19.0.0"
|
"react-dom": "^19.0.0",
|
||||||
|
"validator": "^13.12.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/eslintrc": "^3",
|
"@eslint/eslintrc": "^3",
|
||||||
"@types/bcryptjs": "^2.4.6",
|
"@types/bcryptjs": "^2.4.6",
|
||||||
"@types/node": "^20",
|
"@types/node": "^20",
|
||||||
|
"@types/nodemailer": "^6.4.17",
|
||||||
"@types/react": "^19",
|
"@types/react": "^19",
|
||||||
"@types/react-dom": "^19",
|
"@types/react-dom": "^19",
|
||||||
"eslint": "^9",
|
"eslint": "^9",
|
||||||
|
|||||||
65
yoga-app/src/actions/contactus-actions.ts
Normal file
65
yoga-app/src/actions/contactus-actions.ts
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
'use server'
|
||||||
|
|
||||||
|
import {sendMail} from "@/actions/mail-actions";
|
||||||
|
import {contactUsFormValidator} from "@/validation/validation";
|
||||||
|
import {copyFormValues, copyValidationErrors, FormControl, formDataToJson} from "@/util/form-util";
|
||||||
|
import localize_hu from 'ajv-i18n/localize/hu';
|
||||||
|
|
||||||
|
|
||||||
|
export type ContactFormState = {
|
||||||
|
firstname: FormControl,
|
||||||
|
lastname: FormControl,
|
||||||
|
phone: FormControl,
|
||||||
|
email: FormControl,
|
||||||
|
comment: FormControl,
|
||||||
|
formState: 'empty' | 'invalid' | 'success'
|
||||||
|
}
|
||||||
|
export type ContactFormData = {
|
||||||
|
firstname: string,
|
||||||
|
lastname: string,
|
||||||
|
phone: string,
|
||||||
|
email: string,
|
||||||
|
comment: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sendContactUsMail(prevState: ContactFormState, formState: FormData) {
|
||||||
|
const newState: ContactFormState = {
|
||||||
|
comment: {name: 'comment'}, email: {name: 'email'}, firstname: {name: 'firstname'},
|
||||||
|
lastname: {name: 'lastname'},
|
||||||
|
phone: {name: 'phone'},
|
||||||
|
formState: 'invalid'
|
||||||
|
};
|
||||||
|
const contactUsFormData: ContactFormData = formDataToJson(formState) as ContactFormData;
|
||||||
|
const validationResult = contactUsFormValidator(contactUsFormData);
|
||||||
|
localize_hu(contactUsFormValidator.errors)
|
||||||
|
if (!validationResult) {
|
||||||
|
copyFormValues(newState, contactUsFormData);
|
||||||
|
copyValidationErrors(newState, contactUsFormValidator)
|
||||||
|
} else {
|
||||||
|
sendMail(
|
||||||
|
{
|
||||||
|
email: contactUsFormData.email,
|
||||||
|
sendTo: process.env.SITE_MAIL_RECIEVER,
|
||||||
|
subject: 'Kapcsolat',
|
||||||
|
text: `
|
||||||
|
Kapcsolat üzenet érkezett:
|
||||||
|
Név: ${contactUsFormData.lastname} ${contactUsFormData.firstname}
|
||||||
|
Tel: ${contactUsFormData.phone}
|
||||||
|
Email: ${contactUsFormData.email}
|
||||||
|
Üzenet:
|
||||||
|
${contactUsFormData.comment}
|
||||||
|
`,
|
||||||
|
html:`
|
||||||
|
Kapcsolat üzenet érkezett:
|
||||||
|
<br>Név: ${contactUsFormData.lastname} ${contactUsFormData.firstname}
|
||||||
|
<br>Tel: ${contactUsFormData.phone}
|
||||||
|
<br>Email: ${contactUsFormData.email}
|
||||||
|
<br>Üzenet:
|
||||||
|
<br>${contactUsFormData.comment}
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
newState.formState = 'success';
|
||||||
|
}
|
||||||
|
return newState;
|
||||||
|
}
|
||||||
50
yoga-app/src/actions/mail-actions.ts
Normal file
50
yoga-app/src/actions/mail-actions.ts
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
'use server';
|
||||||
|
import nodemailer from 'nodemailer';
|
||||||
|
const SMTP_SERVER_HOST = process.env.SMTP_SERVER_HOST;
|
||||||
|
const SMTP_SERVER_PORT =parseInt( process.env.SMTP_SERVER_PORT!,10);
|
||||||
|
const SMTP_SERVER_SECURE = "true" == process.env.SMTP_SERVER_SECIRE ;
|
||||||
|
const SMTP_SERVER_USERNAME = process.env.SMTP_SERVER_USERNAME;
|
||||||
|
const SMTP_SERVER_PASSWORD = process.env.SMTP_SERVER_PASSWORD;
|
||||||
|
const SITE_MAIL_RECIEVER = process.env.SITE_MAIL_RECIEVER;
|
||||||
|
const transporter = nodemailer.createTransport({
|
||||||
|
// service: 'gmail',
|
||||||
|
host: SMTP_SERVER_HOST,
|
||||||
|
port: SMTP_SERVER_PORT,
|
||||||
|
secure: SMTP_SERVER_SECURE,
|
||||||
|
auth: {
|
||||||
|
user: SMTP_SERVER_USERNAME,
|
||||||
|
pass: SMTP_SERVER_PASSWORD,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export async function sendMail({
|
||||||
|
email,
|
||||||
|
sendTo,
|
||||||
|
subject,
|
||||||
|
text,
|
||||||
|
html,
|
||||||
|
}: {
|
||||||
|
email: string;
|
||||||
|
sendTo?: string;
|
||||||
|
subject: string;
|
||||||
|
text: string;
|
||||||
|
html?: string;
|
||||||
|
}) {
|
||||||
|
try {
|
||||||
|
const isVerified = await transporter.verify();
|
||||||
|
console.log("isVerified",isVerified)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Something Went Wrong', SMTP_SERVER_USERNAME, SMTP_SERVER_PASSWORD, error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const info = await transporter.sendMail({
|
||||||
|
from: email,
|
||||||
|
to: sendTo || SITE_MAIL_RECIEVER,
|
||||||
|
subject: subject,
|
||||||
|
text: text,
|
||||||
|
html: html ? html : '',
|
||||||
|
});
|
||||||
|
console.log('Message Sent', info.messageId);
|
||||||
|
console.log('Mail sent to',sendTo, SITE_MAIL_RECIEVER);
|
||||||
|
return info;
|
||||||
|
}
|
||||||
@ -1,17 +0,0 @@
|
|||||||
|
|
||||||
export interface HomePageData{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
export interface OurServiceData{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AboutUsData{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface OurSpecialitiesData{
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,10 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import AosComponent from "@/components/aos.component";
|
import AosComponent from "@/components/aos.component";
|
||||||
import OurServicesComponent from "@/components/our.services.component";
|
|
||||||
import OurSpecialitiesComponent from "@/components/our.specialities.component";
|
|
||||||
import ContactUsComponent from "@/components/contact.us.component";
|
|
||||||
import PricingComponent from "@/components/pricing.component";
|
|
||||||
import FeedbackComponent from "@/components/feedbackComponent";
|
|
||||||
import BlogPostsComponent from "@/components/blog.posts.component";
|
import BlogPostsComponent from "@/components/blog.posts.component";
|
||||||
import FooterComponent from "@/components/footer.component";
|
import FooterComponent from "@/components/footer.component";
|
||||||
import SubscribeComponent from "@/components/subscribe.component";
|
import SubscribeComponent from "@/components/subscribe.component";
|
||||||
@ -43,11 +38,6 @@ export default async function About() {
|
|||||||
{ ourVision && <TextWithImageComponent config={ourVision} />}
|
{ ourVision && <TextWithImageComponent config={ourVision} />}
|
||||||
{ achievements && <AchievementsComponent config={achievements}/>}
|
{ achievements && <AchievementsComponent config={achievements}/>}
|
||||||
|
|
||||||
{/*{ ourServices && <OurServicesComponent title={ourServices?.title!} header={ourServices?.header!} description={ourServices?.description!} /> }*/}
|
|
||||||
{/*{ ourSpecialities && <OurSpecialitiesComponent config={ourSpecialities} /> }*/}
|
|
||||||
{/*{ contactUs && <ContactUsComponent contactUs={contactUs}/>}*/}
|
|
||||||
{/*{ prices && <PricingComponent config={prices} /> }*/}
|
|
||||||
{/*{ feedbacks && <FeedbackComponent config={feedbacks} /> }*/}
|
|
||||||
{ blogs && <BlogPostsComponent config={blogs} />}
|
{ blogs && <BlogPostsComponent config={blogs} />}
|
||||||
{ subscribeNow && <SubscribeComponent config={subscribeNow} /> }
|
{ subscribeNow && <SubscribeComponent config={subscribeNow} /> }
|
||||||
{ footer && <FooterComponent config={footer} />}
|
{ footer && <FooterComponent config={footer} />}
|
||||||
@ -59,6 +49,5 @@ export default async function About() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getBreadCrumbName = () => {
|
|
||||||
return "Rólunk;"
|
export const dynamic = 'force-dynamic'
|
||||||
}
|
|
||||||
|
|||||||
@ -4,3 +4,4 @@ export default function BlogListComponent(){
|
|||||||
<div>Blog list</div>
|
<div>Blog list</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
export const dynamic = 'force-dynamic'
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
import strapiApi from "@/api/strapi/strapi-api";
|
import strapiApi from "@/api/strapi/strapi-api";
|
||||||
import SubHeaderComponent from "@/components/subHeader.component";
|
import SubHeaderComponent from "@/components/subHeader.component";
|
||||||
import FaqComponent from "@/components/faq.component";
|
|
||||||
import BlogPostsComponent from "@/components/blog.posts.component";
|
|
||||||
import SubscribeComponent from "@/components/subscribe.component";
|
import SubscribeComponent from "@/components/subscribe.component";
|
||||||
import FooterComponent from "@/components/footer.component";
|
import FooterComponent from "@/components/footer.component";
|
||||||
import AosComponent from "@/components/aos.component";
|
import AosComponent from "@/components/aos.component";
|
||||||
@ -34,3 +32,5 @@ export default async function ContactPage(){
|
|||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const dynamic = 'force-dynamic'
|
||||||
|
|||||||
@ -1,11 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import AosComponent from "@/components/aos.component";
|
import AosComponent from "@/components/aos.component";
|
||||||
import OurServicesComponent from "@/components/our.services.component";
|
|
||||||
import AboutUsComponent from "@/components/about.us.component";
|
|
||||||
import OurSpecialitiesComponent from "@/components/our.specialities.component";
|
|
||||||
import ContactUsComponent from "@/components/contact.us.component";
|
|
||||||
import PricingComponent from "@/components/pricing.component";
|
|
||||||
import FeedbackComponent from "@/components/feedbackComponent";
|
|
||||||
import BlogPostsComponent from "@/components/blog.posts.component";
|
import BlogPostsComponent from "@/components/blog.posts.component";
|
||||||
import FooterComponent from "@/components/footer.component";
|
import FooterComponent from "@/components/footer.component";
|
||||||
import SubscribeComponent from "@/components/subscribe.component";
|
import SubscribeComponent from "@/components/subscribe.component";
|
||||||
@ -24,7 +18,7 @@ export default async function About() {
|
|||||||
footer
|
footer
|
||||||
} = await strapiApi.getFaqPage();
|
} = await strapiApi.getFaqPage();
|
||||||
return (
|
return (
|
||||||
<>
|
<>xxxxx
|
||||||
{ <SubHeaderComponent header1={header} description={description} /> }
|
{ <SubHeaderComponent header1={header} description={description} /> }
|
||||||
{ questionsAndAnswers && <FaqComponent config={questionsAndAnswers} /> }
|
{ questionsAndAnswers && <FaqComponent config={questionsAndAnswers} /> }
|
||||||
{ blogs && <BlogPostsComponent config={blogs} /> }
|
{ blogs && <BlogPostsComponent config={blogs} /> }
|
||||||
@ -36,3 +30,4 @@ export default async function About() {
|
|||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
export const dynamic = 'force-dynamic'
|
||||||
|
|||||||
@ -13,3 +13,4 @@ const Login: React.FC = () => {
|
|||||||
|
|
||||||
|
|
||||||
export default Login;
|
export default Login;
|
||||||
|
|
||||||
|
|||||||
@ -50,3 +50,5 @@ export default async function Home() {
|
|||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const dynamic = 'force-dynamic'
|
||||||
|
|||||||
@ -38,3 +38,5 @@ export default async function PricesPage( ) {
|
|||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const dynamic = 'force-dynamic'
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import AosComponent from "@/components/aos.component";
|
import AosComponent from "@/components/aos.component";
|
||||||
import OurServicesComponent from "@/components/our.services.component";
|
import OurServicesComponent from "@/components/our.services.component";
|
||||||
import AboutUsComponent from "@/components/about.us.component";
|
|
||||||
import OurSpecialitiesComponent from "@/components/our.specialities.component";
|
import OurSpecialitiesComponent from "@/components/our.specialities.component";
|
||||||
import ContactUsComponent from "@/components/contact.us.component";
|
import ContactUsComponent from "@/components/contact.us.component";
|
||||||
import PricingComponent from "@/components/pricing.component";
|
|
||||||
import FeedbackComponent from "@/components/feedbackComponent";
|
import FeedbackComponent from "@/components/feedbackComponent";
|
||||||
import BlogPostsComponent from "@/components/blog.posts.component";
|
import BlogPostsComponent from "@/components/blog.posts.component";
|
||||||
import FooterComponent from "@/components/footer.component";
|
import FooterComponent from "@/components/footer.component";
|
||||||
@ -39,3 +37,5 @@ export default async function Services() {
|
|||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const dynamic = 'force-dynamic'
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import YogaImageComponent from "@/components/yoga.image.component";
|
import YogaImageComponent from "@/components/yoga.image.component";
|
||||||
import {
|
import {
|
||||||
YogaAboutUsComponent,
|
|
||||||
YogaAboutUsComponent_Plain
|
YogaAboutUsComponent_Plain
|
||||||
} from "@/types/generated-strapi-interfaces/api/yoga-about-us-component";
|
} from "@/types/generated-strapi-interfaces/api/yoga-about-us-component";
|
||||||
import {StrapiFile} from "@/types/types";
|
import {StrapiFile} from "@/types/types";
|
||||||
|
|||||||
@ -7,7 +7,7 @@ export interface Props{
|
|||||||
config: YogaAboutUsWithBoxesComponent_Plain
|
config: YogaAboutUsWithBoxesComponent_Plain
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AboutUsWithBoxesComponent({ config: {title,header,description,image, box1,box2,box3,box4}}: Props){
|
export default function AboutUsWithBoxesComponent({ config: {title,header,description, box1,box2,box3,box4}}: Props){
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -8,7 +8,7 @@ export interface Props{
|
|||||||
|
|
||||||
}
|
}
|
||||||
export default function AchievementsItemComponent({achievement
|
export default function AchievementsItemComponent({achievement
|
||||||
:{ image,title}
|
:{ image}
|
||||||
}: Props){
|
}: Props){
|
||||||
const imageFile: StrapiFile = image as StrapiFile;
|
const imageFile: StrapiFile = image as StrapiFile;
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import YogaImageComponent from "@/components/yoga.image.component";
|
import YogaImageComponent from "@/components/yoga.image.component";
|
||||||
import {YogaBlogPostsComponent_Plain} from "@/types/generated-strapi-interfaces/api/yoga-blog-posts-component";
|
|
||||||
import {YogaBlogPost_Plain} from "@/types/generated-strapi-interfaces/api/yoga-blog-post";
|
import {YogaBlogPost_Plain} from "@/types/generated-strapi-interfaces/api/yoga-blog-post";
|
||||||
import {StrapiFile} from "@/types/types";
|
import {StrapiFile} from "@/types/types";
|
||||||
import strapiApi from "@/api/strapi/strapi-api";
|
import strapiApi from "@/api/strapi/strapi-api";
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { useEffect } from "react";
|
|||||||
export default function BootstrapComponent()
|
export default function BootstrapComponent()
|
||||||
{
|
{
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
// @ts-ignore
|
// @ts-expect-error promise
|
||||||
import( "bootstrap/dist/js/bootstrap.bundle")
|
import( "bootstrap/dist/js/bootstrap.bundle")
|
||||||
},[])
|
},[])
|
||||||
return <></>
|
return <></>
|
||||||
|
|||||||
@ -1,12 +1,9 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import React, { ReactNode } from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
import {usePathname, useRouter} from 'next/navigation'
|
import {usePathname} from 'next/navigation'
|
||||||
import Link from 'next/link'
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
}
|
|
||||||
|
|
||||||
const pathToBreadCrumbs = (path: string) => {
|
const pathToBreadCrumbs = (path: string) => {
|
||||||
const mapping: Record<string, string> = {
|
const mapping: Record<string, string> = {
|
||||||
@ -34,13 +31,13 @@ const NextBreadcrumb = () => {
|
|||||||
<div className="btn_wrapper">
|
<div className="btn_wrapper">
|
||||||
<span className="sub_home_span">{pathToBreadCrumbs( "/" )} </span>
|
<span className="sub_home_span">{pathToBreadCrumbs( "/" )} </span>
|
||||||
{
|
{
|
||||||
pathNames.map((value,index) => {
|
pathNames.map((value) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<React.Fragment key={value}>
|
||||||
<i className="fa-solid fa-angles-right" aria-hidden="true"></i>
|
<i className="fa-solid fa-angles-right" aria-hidden="true"></i>
|
||||||
<span className="sub_span">{pathToBreadCrumbs( value )}</span>
|
<span className="sub_span">{pathToBreadCrumbs( value )}</span>
|
||||||
</>
|
</React.Fragment>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,43 @@
|
|||||||
|
'use client'
|
||||||
import YogaImageComponent from "@/components/yoga.image.component";
|
import YogaImageComponent from "@/components/yoga.image.component";
|
||||||
import {YogaContactUs_Plain} from "@/types/generated-strapi-interfaces/api/yoga-contact-us";
|
import {YogaContactUs_Plain} from "@/types/generated-strapi-interfaces/api/yoga-contact-us";
|
||||||
|
import {RefObject, startTransition, useActionState, useEffect, useRef} from "react";
|
||||||
|
import {ContactFormState, sendContactUsMail} from "@/actions/contactus-actions";
|
||||||
|
import clsx from "clsx";
|
||||||
|
|
||||||
export interface Props{
|
export interface Props {
|
||||||
contactUs: YogaContactUs_Plain
|
contactUs: YogaContactUs_Plain
|
||||||
}
|
}
|
||||||
const ContactUsComponent = ( { contactUs :{ header,firstName,lastName,phone,title,message,email,buttonText }}: Props) => {
|
|
||||||
|
const ContactUsComponent = ({
|
||||||
|
contactUs: {
|
||||||
|
header,
|
||||||
|
firstName,
|
||||||
|
lastName,
|
||||||
|
phone,
|
||||||
|
title,
|
||||||
|
message,
|
||||||
|
email,
|
||||||
|
buttonText
|
||||||
|
}
|
||||||
|
}: Props) => {
|
||||||
|
const initialState = () => {
|
||||||
|
return {
|
||||||
|
firstname: {value: ''},
|
||||||
|
lastname: {value: ''},
|
||||||
|
comment: {value: ''},
|
||||||
|
email: {value: ''},
|
||||||
|
phone: {value: ''}
|
||||||
|
} as ContactFormState;
|
||||||
|
}
|
||||||
|
const [state, formAction] = useActionState(sendContactUsMail, initialState());
|
||||||
|
const ref: RefObject<HTMLFormElement|null> = useRef(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if ( state.formState == 'success'){
|
||||||
|
ref.current?.reset()
|
||||||
|
}
|
||||||
|
}, [state]);
|
||||||
return (
|
return (
|
||||||
<section className="get_in_touch_section">
|
<section className="get_in_touch_section">
|
||||||
<div className="container">
|
<div className="container">
|
||||||
@ -13,39 +46,67 @@ const ContactUsComponent = ( { contactUs :{ header,firstName,lastName,phone,ti
|
|||||||
<div className="get_in_touch_content">
|
<div className="get_in_touch_content">
|
||||||
<h5>{title}</h5>
|
<h5>{title}</h5>
|
||||||
<h2>{header}</h2>
|
<h2>{header}</h2>
|
||||||
<form>
|
<form
|
||||||
|
ref={ref}
|
||||||
|
onSubmit={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
startTransition(() => formAction(new FormData(e.currentTarget)));
|
||||||
|
}}
|
||||||
|
>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-lg-6 col-md-6 col-sm-6">
|
<div className="col-lg-6 col-md-6 col-sm-6">
|
||||||
<div className="form-group mb-0">
|
<div className="form-group mb-0">
|
||||||
<input type="text" name="fname" id="fname" className="form-control"
|
<input type="text" name="firstname" id="firstname"
|
||||||
placeholder={firstName}/>
|
className={clsx("form-control", {"mb-0": state.firstname.error})}
|
||||||
|
placeholder={firstName}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{state.firstname.error &&
|
||||||
|
<div className="text-danger mb-3">{state.firstname.error}</div>}
|
||||||
</div>
|
</div>
|
||||||
<div className="col-lg-6 col-md-6 col-sm-6">
|
<div className="col-lg-6 col-md-6 col-sm-6">
|
||||||
<div className="form-group mb-0">
|
<div className="form-group mb-0">
|
||||||
<input type="text" name="lname" id="lname"
|
<input type="text" name="lastname" id="lname"
|
||||||
className="form-control form_style" placeholder={lastName}/>
|
className={clsx("form-control", "form_style", {"mb-0": state.lastname.error})}
|
||||||
|
placeholder={lastName}/>
|
||||||
</div>
|
</div>
|
||||||
|
{state.lastname.error &&
|
||||||
|
<div className="text-danger mb-3">{state.lastname.error}</div>}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className="col-lg-6 col-md-6 col-sm-6">
|
<div className="col-lg-6 col-md-6 col-sm-6">
|
||||||
<div className="form-group mb-0">
|
<div className="form-group mb-0">
|
||||||
<input type="tel" name="phonenum" id="phonenum" className="form-control"
|
<input type="tel" name="phone" id="phonenum"
|
||||||
|
className={clsx("form-control", {"mb-0": state.phone.error})}
|
||||||
|
|
||||||
placeholder={phone}/>
|
placeholder={phone}/>
|
||||||
</div>
|
</div>
|
||||||
|
{state.phone.error &&
|
||||||
|
<div className="text-danger mb-3">{state.phone.error}</div>}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className="col-lg-6 col-md-6 col-sm-6">
|
<div className="col-lg-6 col-md-6 col-sm-6">
|
||||||
<div className="form-group mb-0">
|
<div className="form-group mb-0">
|
||||||
<input type="email" name="emailaddrs" id="emailaddrs"
|
<input type="email" name="email" id="emailaddrs"
|
||||||
className="form-control form_style" placeholder={email}/>
|
className={clsx("form-control", "form_style", {"mb-0": state.email.error})}
|
||||||
|
placeholder={email}/>
|
||||||
</div>
|
</div>
|
||||||
|
{state.email.error &&
|
||||||
|
<div className="text-danger mb-3">{state.email.error}</div>}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
<div className="col-lg-12">
|
<div className="col-lg-12">
|
||||||
<div className=" form-group mb-0">
|
<div className=" form-group mb-0">
|
||||||
<textarea rows={3} name="comment" id="msg" className="form-control"
|
<textarea rows={3} name="comment" id="msg"
|
||||||
|
className={clsx("form-control", {"mb-0": state.comment.error})}
|
||||||
|
|
||||||
placeholder={message}></textarea>
|
placeholder={message}></textarea>
|
||||||
</div>
|
</div>
|
||||||
|
{state.comment.error &&
|
||||||
|
<div className="text-danger mb-3">{state.comment.error}</div>}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="btn_wrapper">
|
<div className="btn_wrapper">
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
import {YogaFaqComponent_Plain} from "@/types/generated-strapi-interfaces/api/yoga-faq-component";
|
import {YogaFaqComponent_Plain} from "@/types/generated-strapi-interfaces/api/yoga-faq-component";
|
||||||
import {useState} from "react";
|
import {useState} from "react";
|
||||||
import FaqQaComponent from "@/components/faq.qa.component";
|
import FaqQaComponent from "@/components/faq.qa.component";
|
||||||
import { MouseEvent } from 'react'
|
|
||||||
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
@ -53,6 +52,7 @@ export default function FaqComponent({
|
|||||||
questionsAndAnswers.map((qa, index) => {
|
questionsAndAnswers.map((qa, index) => {
|
||||||
return (
|
return (
|
||||||
<FaqQaComponent
|
<FaqQaComponent
|
||||||
|
key={qa.id}
|
||||||
qa={qa}
|
qa={qa}
|
||||||
id={index}
|
id={index}
|
||||||
onClick={onQAClick}
|
onClick={onQAClick}
|
||||||
|
|||||||
@ -2,27 +2,18 @@ import YogaImageComponent from "@/components/yoga.image.component";
|
|||||||
import {YogaFaqQa_Plain} from "@/types/generated-strapi-interfaces/api/yoga-faq-qa";
|
import {YogaFaqQa_Plain} from "@/types/generated-strapi-interfaces/api/yoga-faq-qa";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
|
|
||||||
import classes from "./faq.qa.module.scss";
|
|
||||||
import {useEffect, useState} from "react";
|
|
||||||
|
|
||||||
export interface Props{
|
export interface Props{
|
||||||
id: number,
|
id: number,
|
||||||
qa: YogaFaqQa_Plain,
|
qa: YogaFaqQa_Plain,
|
||||||
isOpen: boolean,
|
isOpen: boolean,
|
||||||
onClick: (id: number) => void
|
onClick: (id: number) => void
|
||||||
}
|
}
|
||||||
export default function FaqQaComponent({id,qa,isOpen,onClick}: Props){
|
export default function FaqQaComponent({id,qa,isOpen}: Props){
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="accordion-card">
|
<div className="accordion-card">
|
||||||
<div className="card-header" id={"heading" + id}>
|
<div className="card-header" id={"heading" + id}>
|
||||||
<a href="#"
|
<a href="#"
|
||||||
// onClick={ (event) => {
|
|
||||||
// event.preventDefault();
|
|
||||||
// onClick(id)
|
|
||||||
// }}
|
|
||||||
className={clsx("btn", "btn-link", {"collapsed": !isOpen})}
|
className={clsx("btn", "btn-link", {"collapsed": !isOpen})}
|
||||||
data-toggle="collapse" data-target={"#collapse" + id}
|
data-toggle="collapse" data-target={"#collapse" + id}
|
||||||
aria-expanded="false" aria-controls={"collapse" + id}>
|
aria-expanded="false" aria-controls={"collapse" + id}>
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import {
|
import {
|
||||||
YogaGoogleMapsComponent,
|
|
||||||
YogaGoogleMapsComponent_Plain
|
YogaGoogleMapsComponent_Plain
|
||||||
} from "@/types/generated-strapi-interfaces/api/yoga-google-maps-component";
|
} from "@/types/generated-strapi-interfaces/api/yoga-google-maps-component";
|
||||||
|
|
||||||
|
|||||||
@ -20,7 +20,7 @@ const ITypedComponent = ( {text}: Props ) => {
|
|||||||
loop: true
|
loop: true
|
||||||
})
|
})
|
||||||
setReady(true)
|
setReady(true)
|
||||||
}, [ready]);
|
}, [ready,text]);
|
||||||
return (<></> );
|
return (<></> );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -6,10 +6,8 @@ export interface Props{
|
|||||||
const MainHeaderComponent = ({ config: {
|
const MainHeaderComponent = ({ config: {
|
||||||
title,
|
title,
|
||||||
header,
|
header,
|
||||||
headerIType,
|
|
||||||
description,
|
description,
|
||||||
button,
|
button,
|
||||||
image
|
|
||||||
|
|
||||||
}}: Props) => {
|
}}: Props) => {
|
||||||
|
|
||||||
|
|||||||
@ -2,7 +2,6 @@
|
|||||||
import {FC} from "react";
|
import {FC} from "react";
|
||||||
import YogaImageComponent from "@/components/yoga.image.component";
|
import YogaImageComponent from "@/components/yoga.image.component";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
import exp from "node:constants";
|
|
||||||
|
|
||||||
export interface MenuItem{
|
export interface MenuItem{
|
||||||
href?: string;
|
href?: string;
|
||||||
|
|||||||
@ -1,7 +1,4 @@
|
|||||||
import YogaImageComponent from "@/components/yoga.image.component";
|
import YogaImageComponent from "@/components/yoga.image.component";
|
||||||
import {
|
|
||||||
OurSpecialitiesComponent_Plain
|
|
||||||
} from "@/types/generated-strapi-interfaces/components/yoga-site/OurSpecialitiesComponent";
|
|
||||||
import OurSpecialitiesItemComponent from "@/components/our.specialities.item.component";
|
import OurSpecialitiesItemComponent from "@/components/our.specialities.item.component";
|
||||||
import {YogaSpecialitiesComponent_Plain} from "@/types/generated-strapi-interfaces/api/yoga-specialities-component";
|
import {YogaSpecialitiesComponent_Plain} from "@/types/generated-strapi-interfaces/api/yoga-specialities-component";
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,3 @@
|
|||||||
import YogaImageComponent from "@/components/yoga.image.component";
|
|
||||||
import {
|
|
||||||
OurSpecialitiesComponent_Plain
|
|
||||||
} from "@/types/generated-strapi-interfaces/components/yoga-site/OurSpecialitiesComponent";
|
|
||||||
import {TitleDescription_Plain} from "@/types/generated-strapi-interfaces/components/shared/TitleDescription";
|
import {TitleDescription_Plain} from "@/types/generated-strapi-interfaces/components/shared/TitleDescription";
|
||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
import YogaImageComponent from "@/components/yoga.image.component";
|
|
||||||
import {YogaPriceComponent_Plain} from "@/types/generated-strapi-interfaces/api/yoga-price-component";
|
import {YogaPriceComponent_Plain} from "@/types/generated-strapi-interfaces/api/yoga-price-component";
|
||||||
import {PriceItemComponent} from "@/components/price.item.component";
|
import {PriceItemComponent} from "@/components/price.item.component";
|
||||||
|
|
||||||
|
|||||||
@ -5,10 +5,9 @@ import {HeaderB} from "@/types/generated-strapi-interfaces/components/yoga-site/
|
|||||||
import NextBreadcrumb from "@/components/breadcrumbs.component";
|
import NextBreadcrumb from "@/components/breadcrumbs.component";
|
||||||
|
|
||||||
|
|
||||||
export interface Props extends HeaderB{
|
export type Props = HeaderB ;
|
||||||
}
|
|
||||||
|
|
||||||
const SubHeaderComponent = ({header1,header2,description}: Props) =>{
|
const SubHeaderComponent = ({header1,description}: Props) =>{
|
||||||
return (
|
return (
|
||||||
<div className="sub-banner-section">
|
<div className="sub-banner-section">
|
||||||
<Nav menuItems={MAIN_MENU} />
|
<Nav menuItems={MAIN_MENU} />
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import {
|
|||||||
import clsx from "clsx";
|
import clsx from "clsx";
|
||||||
export interface Props{
|
export interface Props{
|
||||||
config: YogaSubscribeNowComponent_Plain,
|
config: YogaSubscribeNowComponent_Plain,
|
||||||
styleClass: string
|
styleClass?: string
|
||||||
}
|
}
|
||||||
const SubscribeComponent = ({
|
const SubscribeComponent = ({
|
||||||
config: {title,header,placeHolderEmail,buttonSubscribeLabel},
|
config: {title,header,placeHolderEmail,buttonSubscribeLabel},
|
||||||
|
|||||||
@ -11,6 +11,7 @@ export interface Properties {
|
|||||||
|
|
||||||
const YogaImageComponent = ( {src,alt,className,style}: Properties ) => {
|
const YogaImageComponent = ( {src,alt,className,style}: Properties ) => {
|
||||||
return (
|
return (
|
||||||
|
/* eslint-disable @next/next/no-img-element */
|
||||||
<img src={src} alt={alt || ""} className={ clsx( className )} style={style} />
|
<img src={src} alt={alt || ""} className={ clsx( className )} style={style} />
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ export interface Article {
|
|||||||
cover?: { data: Media };
|
cover?: { data: Media };
|
||||||
author?: { data: Author };
|
author?: { data: Author };
|
||||||
category?: { data: Category };
|
category?: { data: Category };
|
||||||
blocks?: any;
|
blocks?: object;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
export interface Article_Plain {
|
export interface Article_Plain {
|
||||||
@ -28,7 +28,7 @@ export interface Article_Plain {
|
|||||||
cover?: Media_Plain;
|
cover?: Media_Plain;
|
||||||
author?: Author_Plain;
|
author?: Author_Plain;
|
||||||
category?: Category_Plain;
|
category?: Category_Plain;
|
||||||
blocks?: any;
|
blocks?: object;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Article_NoRelations {
|
export interface Article_NoRelations {
|
||||||
@ -39,7 +39,7 @@ export interface Article_NoRelations {
|
|||||||
cover?: number;
|
cover?: number;
|
||||||
author?: number;
|
author?: number;
|
||||||
category?: number;
|
category?: number;
|
||||||
blocks?: any;
|
blocks?: object;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Article_AdminPanelLifeCycle {
|
export interface Article_AdminPanelLifeCycle {
|
||||||
@ -50,5 +50,5 @@ export interface Article_AdminPanelLifeCycle {
|
|||||||
cover?: AdminPanelRelationPropertyModification<Media_Plain>;
|
cover?: AdminPanelRelationPropertyModification<Media_Plain>;
|
||||||
author?: AdminPanelRelationPropertyModification<Author_Plain>;
|
author?: AdminPanelRelationPropertyModification<Author_Plain>;
|
||||||
category?: AdminPanelRelationPropertyModification<Category_Plain>;
|
category?: AdminPanelRelationPropertyModification<Category_Plain>;
|
||||||
blocks?: any;
|
blocks?: object;
|
||||||
}
|
}
|
||||||
|
|||||||
53
yoga-app/src/util/form-util.ts
Normal file
53
yoga-app/src/util/form-util.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import {ValidateFunction} from "ajv";
|
||||||
|
|
||||||
|
export type FormControl = {
|
||||||
|
name: string,
|
||||||
|
value?: string,
|
||||||
|
error?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export function formDataToJson(formData: FormData) {
|
||||||
|
const object: Record<string, string | string[] | File | File[]> = {};
|
||||||
|
formData.forEach((value, key) => {
|
||||||
|
if ( key == 'formState'){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Reflect.has in favor of: object.hasOwnProperty(key)
|
||||||
|
if (!Reflect.has(object, key)) {
|
||||||
|
object[key] = value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!Array.isArray(object[key])) {
|
||||||
|
object[key] = [];
|
||||||
|
}
|
||||||
|
if (value instanceof File) {
|
||||||
|
(object[key] as File[]).push(value);
|
||||||
|
} else {
|
||||||
|
(object[key] as string[]).push(value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
export function copyFormValues(form: Record<string, FormControl|string|any>,jsonFormData: Record<string, FormDataEntryValue>){
|
||||||
|
const keys = Object.getOwnPropertyNames(form);
|
||||||
|
for(const key of keys){
|
||||||
|
if (key == 'formState'){
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const formControl: FormControl = form[key];
|
||||||
|
formControl.value = jsonFormData[key] as string;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
export function copyValidationErrors(form: Record<string, FormControl|string|any >,validateFunction: ValidateFunction){
|
||||||
|
const keys = Object.getOwnPropertyNames(form);
|
||||||
|
for(const key of keys){
|
||||||
|
const formControl: FormControl = form[key];
|
||||||
|
if ( key == 'formState') continue;
|
||||||
|
formControl.error = validateFunction.errors?.find( err => err.instancePath =="/"+key)?.message;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
23
yoga-app/src/validation/validation.ts
Normal file
23
yoga-app/src/validation/validation.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import Ajv, {JSONSchemaType} from "ajv"
|
||||||
|
import addFormats from "ajv-formats"
|
||||||
|
import {ContactFormData} from "@/actions/contactus-actions";
|
||||||
|
|
||||||
|
const ajv = new Ajv({allErrors: true}) // options can be passed, e.g. {allErrors: true}
|
||||||
|
addFormats(ajv)
|
||||||
|
|
||||||
|
const contactUsFormSchema: JSONSchemaType<ContactFormData> = {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
firstname: {type: "string",minLength: 3,maxLength: 20},
|
||||||
|
lastname: {type: "string",minLength: 3,maxLength: 20},
|
||||||
|
phone: {type: "string",minLength: 3,maxLength: 20},
|
||||||
|
email: {type: "string", format: 'email'},
|
||||||
|
comment: {type: "string",minLength: 3,maxLength: 500}
|
||||||
|
},
|
||||||
|
required: ["firstname","lastname","phone","email","comment"],
|
||||||
|
additionalProperties: true
|
||||||
|
}
|
||||||
|
|
||||||
|
export const contactUsFormValidator = ajv.compile(contactUsFormSchema)
|
||||||
|
|
||||||
|
|
||||||
@ -7,11 +7,11 @@ ENV NODE_ENV=${NODE_ENV}
|
|||||||
WORKDIR /opt/
|
WORKDIR /opt/
|
||||||
COPY package.json package-lock.json ./
|
COPY package.json package-lock.json ./
|
||||||
RUN npm install -g node-gyp
|
RUN npm install -g node-gyp
|
||||||
RUN npm config set fetch-retry-maxtimeout 600000 -g && npm install --only=production
|
RUN npm config set fetch-retry-maxtimeout 600000 -g && npm install --only=production --debug
|
||||||
ENV PATH=/opt/node_modules/.bin:$PATH
|
ENV PATH=/opt/node_modules/.bin:$PATH
|
||||||
WORKDIR /opt/app
|
WORKDIR /opt/app
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN npm run build
|
RUN npm run build --debug
|
||||||
|
|
||||||
# Creating final production image
|
# Creating final production image
|
||||||
FROM node:18-alpine
|
FROM node:18-alpine
|
||||||
|
|||||||
31
yoga-cms/Dockerfile.prod
Normal file
31
yoga-cms/Dockerfile.prod
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# Creating multi-stage build for production
|
||||||
|
FROM node:18-alpine as build
|
||||||
|
RUN apk update && apk add --no-cache build-base gcc autoconf automake zlib-dev libpng-dev vips-dev git > /dev/null 2>&1
|
||||||
|
ARG NODE_ENV=production
|
||||||
|
ENV NODE_ENV=${NODE_ENV}
|
||||||
|
|
||||||
|
WORKDIR /opt/
|
||||||
|
COPY package.json package-lock.json ./
|
||||||
|
RUN npm install -g node-gyp
|
||||||
|
RUN npm config set fetch-retry-maxtimeout 600000 -g && npm install --only=production --debug
|
||||||
|
ENV PATH=/opt/node_modules/.bin:$PATH
|
||||||
|
WORKDIR /opt/app
|
||||||
|
COPY . .
|
||||||
|
RUN pwd && ls -lah
|
||||||
|
RUN npm run build --debug
|
||||||
|
|
||||||
|
# Creating final production image
|
||||||
|
FROM node:18-alpine
|
||||||
|
# RUN apk add --no-cache vips-dev
|
||||||
|
# ARG NODE_ENV=production
|
||||||
|
# ENV NODE_ENV=${NODE_ENV}
|
||||||
|
# WORKDIR /opt/
|
||||||
|
# COPY --from=build /opt/node_modules ./node_modules
|
||||||
|
# WORKDIR /opt/app
|
||||||
|
# COPY --from=build /opt/app ./
|
||||||
|
# ENV PATH=/opt/node_modules/.bin:$PATH
|
||||||
|
|
||||||
|
# RUN chown -R node:node /opt/app
|
||||||
|
USER node
|
||||||
|
EXPOSE 1337
|
||||||
|
# CMD ["npm", "run", "start"]
|
||||||
Loading…
Reference in New Issue
Block a user