added organ
This commit is contained in:
parent
aa8d8a7185
commit
3c88624095
|
@ -0,0 +1,41 @@
|
||||||
|
import React from 'react'
|
||||||
|
import ResponsiveNav from "@/components/Navbar/ResponsiveNav";
|
||||||
|
import { fetchCourses, fetchSettings, fetchOrgan } from "@/utils";
|
||||||
|
import {OrganProps } from "@/types";
|
||||||
|
import Home from '@/components/Organ/Home';
|
||||||
|
|
||||||
|
async function getCourses() {
|
||||||
|
const courses = await fetchCourses();
|
||||||
|
return courses;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getOrgan() {
|
||||||
|
const organ: OrganProps[] = await fetchOrgan();
|
||||||
|
return organ;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getSettings() {
|
||||||
|
const settings = await fetchSettings();
|
||||||
|
return settings;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const metadata = {
|
||||||
|
title: "All In One",
|
||||||
|
description: "**",
|
||||||
|
}
|
||||||
|
|
||||||
|
export default async function Page() {
|
||||||
|
const courses = await getCourses();
|
||||||
|
const settings = await getSettings();
|
||||||
|
const organ = await getOrgan();
|
||||||
|
//const course = await getCourse(params.slug);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='bg-[#F6E8E9]'>
|
||||||
|
|
||||||
|
<ResponsiveNav courses={courses} settings={settings} />
|
||||||
|
<Home settings={settings} organ={organ} />
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
|
@ -65,9 +65,16 @@ const MobileNav = ({ showNav, courses }: Props) => {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<div className='w-full h-16 flex justify-start items-center border-b-[1.5px] border-[#F5DADF]'>
|
||||||
|
<Link key={"03"} href="/electronicorgan" >
|
||||||
|
<p className="text-xl ml-6 text-black">
|
||||||
|
電子管風琴
|
||||||
|
</p>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className='w-full h-16 flex justify-start items-center border-b-[1.5px] border-[#F5DADF]'>
|
<div className='w-full h-16 flex justify-start items-center border-b-[1.5px] border-[#F5DADF]'>
|
||||||
<Link key={"03"} href="/aboutus" >
|
<Link key={"04"} href="/aboutus" >
|
||||||
<p className="text-xl ml-6 text-black">
|
<p className="text-xl ml-6 text-black">
|
||||||
關於我們
|
關於我們
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -65,7 +65,12 @@ const Nav = ({ openNav, courses, showNav, settings }: Props) => {
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<Link key={"03"} href="/aboutus" >
|
<Link key={"03"} href="/electronicorgan" >
|
||||||
|
<p className="nav__link">
|
||||||
|
{"電子管風琴"}
|
||||||
|
</p>
|
||||||
|
</Link>
|
||||||
|
<Link key={"04"} href="/aboutus" >
|
||||||
<p className="nav__link">
|
<p className="nav__link">
|
||||||
{"關於我們"}
|
{"關於我們"}
|
||||||
</p>
|
</p>
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { OrganProps } from '@/types'
|
||||||
|
const AboutusContent = ({ organ }: { organ: OrganProps[] }) => {
|
||||||
|
return (
|
||||||
|
<div className='relative flex flex-col bg-[#F6E8E9] w-full h-auto items-center pb-30 lg:pt-36 pt-10'>
|
||||||
|
{
|
||||||
|
organ.map((item, index) => {
|
||||||
|
const isEven = index % 2 === 0;
|
||||||
|
return (
|
||||||
|
<div key={index}>
|
||||||
|
<div className="hidden lg:flex relative w-[80vw] lg:mb-28 mb-10">
|
||||||
|
{isEven ? (
|
||||||
|
<div className='lg:grid lg:grid-cols-2 w-[80vw] mb-28'>
|
||||||
|
<div className="flex col-span-1 h-auto w-full ">
|
||||||
|
<img
|
||||||
|
src={`${process.env.NEXT_PUBLIC_IMAGE_URL}${item.image}`}
|
||||||
|
alt="Course Image"
|
||||||
|
className="w-full h-[25vw] object-cover object-center rounded-lg shadow-md"
|
||||||
|
style={{ aspectRatio: '1 / 1' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="relative flex col-span-1 w-full h-auto ml-16 items-center">
|
||||||
|
<div className="relative flex flex-col items-start w-[30vw]">
|
||||||
|
<p className="text-4xl">
|
||||||
|
{item.title}
|
||||||
|
</p>
|
||||||
|
{/* <p className="text-base overflow-hidden mt-8">
|
||||||
|
{item.description}
|
||||||
|
</p> */}
|
||||||
|
<div
|
||||||
|
className='mt-8 [&_*]:!text-[1.0rem] [&_*]:!text-gray-600 [&_*]:!bg-transparent'
|
||||||
|
dangerouslySetInnerHTML={{ __html: item.description }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className='lg:grid lg:grid-cols-2 w-[80vw] mb-28'>
|
||||||
|
<div className="relative flex col-span-1 w-full h-auto ml-16 items-center">
|
||||||
|
<div className="relative flex flex-col items-start w-[30vw]">
|
||||||
|
<p className="text-4xl">
|
||||||
|
{item.title}
|
||||||
|
</p>
|
||||||
|
{/* <p className="text-base overflow-hidden mt-8">
|
||||||
|
{item.description}
|
||||||
|
</p> */}
|
||||||
|
<div
|
||||||
|
className='mt-8 [&_*]:!text-[1.0rem] [&_*]:!text-gray-600 [&_*]:!text-start [&_*]:!bg-transparent'
|
||||||
|
dangerouslySetInnerHTML={{ __html: item.description }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex col-span-1 h-auto w-full justify-end ">
|
||||||
|
<img
|
||||||
|
src={`${process.env.NEXT_PUBLIC_IMAGE_URL}${item.image}`}
|
||||||
|
alt="Course Image"
|
||||||
|
className="w-full h-[25vw] object-cover object-center rounded-lg shadow-md"
|
||||||
|
style={{ aspectRatio: '1 / 1' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
)}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col relative w-[80vw] lg:mb-28 mb-10 lg:hidden">
|
||||||
|
<div className="flex col-span-1 h-auto w-full ">
|
||||||
|
<img
|
||||||
|
src={`${process.env.NEXT_PUBLIC_IMAGE_URL}${item.image}`}
|
||||||
|
alt="Course Image"
|
||||||
|
className="w-full h-[44vw] object-cover object-center rounded-lg shadow-md"
|
||||||
|
style={{ aspectRatio: '1 / 1' }}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="relative flex flex-col lg:mt-0 mt-8">
|
||||||
|
<p className="lg:text-4xl text-2xl">
|
||||||
|
{item.title}
|
||||||
|
</p>
|
||||||
|
{/* <p className="text-base overflow-hidden mt-8">
|
||||||
|
{item.description}
|
||||||
|
</p> */}
|
||||||
|
<div
|
||||||
|
className='mt-8 [&_*]:!text-[1.0rem] [&_*]:!text-gray-600 [&_*]:!bg-transparent'
|
||||||
|
dangerouslySetInnerHTML={{ __html: item.description }}
|
||||||
|
/>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
</div >
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AboutusContent
|
|
@ -0,0 +1,28 @@
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const Banner = () => {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='relative flex w-full h-[30vh] lg:h-[50vh] bg-[#E5C6C8] items-center'>
|
||||||
|
|
||||||
|
|
||||||
|
<div className='flex-col flex lg:ml-48 ml-4 z-10'>
|
||||||
|
<p className='text-black lg:text-5xl text-2xl font-bold text-center'>
|
||||||
|
{"電子管風琴"}
|
||||||
|
</p>
|
||||||
|
<img src={"/images/line.png"} className='lg:w-[35vh] h-auto object-cover mt-2' />
|
||||||
|
</div>
|
||||||
|
{/* <div className='absolute bottom-0 right-0 max-sm:-right-32 md:-right-32 lg:right-32 bg-[url("/images/kid2.png")] bg-cover bg-center bg-no-repeat h-full w-[80%]'></div> */}
|
||||||
|
<div className=" w-full h-full">
|
||||||
|
<img
|
||||||
|
src={"/images/piano1.jpg"}
|
||||||
|
alt="piano1"
|
||||||
|
className="absolute right-0 object-cover object-left w-full h-full"
|
||||||
|
/>
|
||||||
|
<div className="absolute inset-0 bg-gradient-to-l from-transparent to-[#D4A3B0] opacity-100"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default Banner
|
|
@ -0,0 +1,47 @@
|
||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useState, useEffect, Suspense } from "react";
|
||||||
|
import Loading from '../Loading'
|
||||||
|
import Footer from '../Footer'
|
||||||
|
import ContactForm from "../ContactForm";
|
||||||
|
import AboutusContent from "./AboutusContent";
|
||||||
|
import Banner from "./Banner";
|
||||||
|
import Map from "./Map";
|
||||||
|
import { SettingsProps, OrganProps } from "@/types";
|
||||||
|
|
||||||
|
const Home = ({ settings, organ }: { settings: SettingsProps, organ: OrganProps[] }) => {
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
// const [courses, setCourses] = useState<CoursesProps[]>([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const loadCourses = async () => {
|
||||||
|
setLoading(true);
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 300)); // 0.5 second delay
|
||||||
|
setLoading(false);
|
||||||
|
}; loadCourses();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const startLoading = () => setLoading(true);
|
||||||
|
const stopLoading = () => setLoading(false);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='bg-[#F2D5D5] sm:bg-[#FFF9F9]'>
|
||||||
|
{loading ? (
|
||||||
|
<div className="flex justify-center items-center h-screen">
|
||||||
|
<Suspense fallback={<div>Loading...</div>}>
|
||||||
|
<Loading />
|
||||||
|
</Suspense>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
<Banner />
|
||||||
|
<AboutusContent organ={organ} />
|
||||||
|
{/* <Map settings={settings} /> */}
|
||||||
|
<ContactForm startLoading={startLoading} stopLoading={stopLoading} />
|
||||||
|
<Footer settings={settings} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default Home
|
|
@ -0,0 +1,97 @@
|
||||||
|
"use client"
|
||||||
|
import React,{useEffect} from 'react'
|
||||||
|
import { GoogleMap, LoadScript, Marker } from '@react-google-maps/api';
|
||||||
|
import Loading from '../Loading'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import { SettingsProps } from '@/types';
|
||||||
|
import { HiLocationMarker } from "react-icons/hi";
|
||||||
|
import { MdEmail } from "react-icons/md";
|
||||||
|
import { FaPhone } from "react-icons/fa6";
|
||||||
|
import mailgo from "mailgo";
|
||||||
|
const containerStyle = {
|
||||||
|
width: '100%',
|
||||||
|
height: '100%'
|
||||||
|
};
|
||||||
|
const Map = ({ settings }: { settings: SettingsProps }) => {
|
||||||
|
const center = {
|
||||||
|
lat: settings.latitude,
|
||||||
|
lng: settings.longitude,
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
mailgo();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='relative flex flex-col w-full h-auto items-center pb-30 bg-[#F6E8E9]'>
|
||||||
|
<div className='flex-col flex w-[80vw] h-[40vw] items-center rounded-lg overflow-hidden'>
|
||||||
|
<LoadScript googleMapsApiKey="AIzaSyBp6yD01sMuqJh2_OqmTjIUQa24Ykhn3Bo" loadingElement={<Loading />}>
|
||||||
|
<GoogleMap
|
||||||
|
mapContainerStyle={containerStyle}
|
||||||
|
zoom={18}
|
||||||
|
center={center}
|
||||||
|
>
|
||||||
|
<Marker key={"1"} position={center}
|
||||||
|
// icon={{ url: '/images/smalllogo.png', scaledSize: new window.google.maps.Size(40, 40) }}
|
||||||
|
/>
|
||||||
|
</GoogleMap>
|
||||||
|
</LoadScript>
|
||||||
|
</div>
|
||||||
|
<div className="flex justify-start w-[80vw] mt-10 mb-32">
|
||||||
|
<div className="flex flex-col lg:flex-row justify-between w-[70vw] ">
|
||||||
|
<div className='flex flex-row'>
|
||||||
|
<div className='flex h-6 w-6 min-w-[1.5rem] min-h-[1.5rem] justify-center items-center rounded-full bg-mainColor'>
|
||||||
|
<HiLocationMarker className='text-white' size={12} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='flex flex-col ml-3'>
|
||||||
|
<p>
|
||||||
|
{"地址"}
|
||||||
|
</p>
|
||||||
|
<button className='text-gray-700 hover:text-mainColor text-left'
|
||||||
|
onClick={() => { window.open(`https://maps.google.com/?q=${settings.latitude},${settings.longitude}`, '_blank') }}>
|
||||||
|
{settings.address}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div className='flex flex-row'>
|
||||||
|
<div className='flex h-6 w-6 items-center justify-center rounded-full bg-mainColor'>
|
||||||
|
<MdEmail className='text-white' size={12} />
|
||||||
|
</div>
|
||||||
|
<div className='flex flex-col ml-3'>
|
||||||
|
<p>
|
||||||
|
{"電郵"}
|
||||||
|
</p>
|
||||||
|
<Link href={`mailto:${settings.email}`}>
|
||||||
|
<p className='text-gray-700 hover:text-mainColor'>
|
||||||
|
{settings.email}
|
||||||
|
</p>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div className='flex flex-row'>
|
||||||
|
|
||||||
|
<div className='flex h-6 w-6 items-center justify-center rounded-full bg-mainColor'>
|
||||||
|
<FaPhone className='text-white' size={12} />
|
||||||
|
</div>
|
||||||
|
<div className='flex flex-col ml-3'>
|
||||||
|
<p>
|
||||||
|
{"電話"}
|
||||||
|
</p>
|
||||||
|
<Link href={`tel:${settings.phone}`}>
|
||||||
|
<p className='text-gray-700 hover:text-mainColor'>
|
||||||
|
{settings.phone}
|
||||||
|
</p>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Map
|
|
@ -25,6 +25,14 @@ export interface AboutusProps {
|
||||||
index: number;
|
index: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface OrganProps {
|
||||||
|
id: string;
|
||||||
|
title: string;
|
||||||
|
description: string
|
||||||
|
image: string;
|
||||||
|
index: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface MessageProps {
|
export interface MessageProps {
|
||||||
name: string,
|
name: string,
|
||||||
phone: string,
|
phone: string,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
import { CoursesProps, CoursesArrayProps, SettingsProps, MessageProps, AboutusProps } from "@/types";
|
import { CoursesProps, CoursesArrayProps, SettingsProps, MessageProps, AboutusProps, OrganProps } from "@/types";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -37,6 +37,28 @@ export async function postMessage(data: MessageProps) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function fetchOrgan() {
|
||||||
|
const headers: HeadersInit = {
|
||||||
|
accept: "application/json"
|
||||||
|
};
|
||||||
|
const url = `${process.env.NEXT_PUBLIC_API_URL}organ/`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await fetch(url, { headers });
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
|
||||||
|
// Sort the result by index
|
||||||
|
const sortedResult: OrganProps[] = result.data.sort((a: any, b: any) => a.index - b.index);
|
||||||
|
|
||||||
|
return sortedResult;
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
console.error('Fetch error:', error);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function fetchAboutus() {
|
export async function fetchAboutus() {
|
||||||
const headers: HeadersInit = {
|
const headers: HeadersInit = {
|
||||||
accept: "application/json"
|
accept: "application/json"
|
||||||
|
|
Loading…
Reference in New Issue