updated
This commit is contained in:
102
components/Aboutus/AboutusContent.tsx
Normal file
102
components/Aboutus/AboutusContent.tsx
Normal file
@@ -0,0 +1,102 @@
|
||||
import React from 'react'
|
||||
import { CoursesProps, AboutusProps } from '@/types'
|
||||
const AboutusContent = ({ aboutus }: { aboutus: AboutusProps[] }) => {
|
||||
return (
|
||||
<div className='relative flex flex-col bg-[#F6E8E9] w-full h-auto items-center pb-30 lg:pt-36 pt-10'>
|
||||
{
|
||||
aboutus.map((item, index) => {
|
||||
const isEven = index % 2 === 0;
|
||||
return (
|
||||
<div>
|
||||
<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={`http://localhost/${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 [&_*]'
|
||||
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'
|
||||
dangerouslySetInnerHTML={{ __html: item.description }}
|
||||
/>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex col-span-1 h-auto w-full justify-end ">
|
||||
<img
|
||||
src={`http://localhost/${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={`http://localhost/${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-3xl">
|
||||
{item.title}
|
||||
</p>
|
||||
{/* <p className="text-base overflow-hidden mt-8">
|
||||
{item.description}
|
||||
</p> */}
|
||||
<div
|
||||
className='mt-8 [&_*]:!text-[1.0rem] [&_*]:!text-gray-600 [&_*]'
|
||||
dangerouslySetInnerHTML={{ __html: item.description }}
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
</div >
|
||||
)
|
||||
}
|
||||
|
||||
export default AboutusContent
|
28
components/Aboutus/Banner.tsx
Normal file
28
components/Aboutus/Banner.tsx
Normal file
@@ -0,0 +1,28 @@
|
||||
import React from 'react'
|
||||
import { CoursesProps } from '@/types'
|
||||
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-3xl 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
|
47
components/Aboutus/Home.tsx
Normal file
47
components/Aboutus/Home.tsx
Normal file
@@ -0,0 +1,47 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect, lazy, 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 { CoursesArrayProps, CoursesProps, SettingsProps, AboutusProps } from "@/types";
|
||||
import Whatsapp from "../Whatsapp";
|
||||
const Home = ({ courses, settings, aboutus }: { courses: CoursesProps[], settings: SettingsProps, aboutus: AboutusProps[] }) => {
|
||||
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]'>
|
||||
{loading ? (
|
||||
<div className="flex justify-center items-center h-screen">
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<Loading />
|
||||
</Suspense>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<Banner />
|
||||
<AboutusContent aboutus={aboutus} />
|
||||
<Map settings={settings} />
|
||||
<ContactForm startLoading={startLoading} stopLoading={stopLoading} />
|
||||
<Footer settings={settings} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default Home
|
96
components/Aboutus/Map.tsx
Normal file
96
components/Aboutus/Map.tsx
Normal file
@@ -0,0 +1,96 @@
|
||||
"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 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'
|
||||
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
|
@@ -34,72 +34,6 @@ async function reorganizedSchedule(schedule: ScheduleProps[]) {
|
||||
const Accordion = async ({ courseData }: { courseData: CoursesProps }) => {
|
||||
const newSchedule = await reorganizedSchedule(courseData.schedule)
|
||||
|
||||
const fakeData = [
|
||||
{
|
||||
"yearAndMonth": "2024年10月",
|
||||
"schedule": [
|
||||
{
|
||||
"info2": "A room, 14F, Sha Tin Market, N.T.",
|
||||
"info1": "11:00-12:00, 13:00-14:00, 15:00-16:00, 17:00-18:00",
|
||||
"id": "e19a7934-82fe-4027-aca6-57a419e9623e",
|
||||
"title": "A班",
|
||||
"date": "2024-10-05T01:30:00Z",
|
||||
"course_id": "29ab193d-2927-459d-9277-5520771b2dd6"
|
||||
},
|
||||
{
|
||||
"info2": "Room B, Sheung Shui Village, N.T.",
|
||||
"info1": "11:00-12:00, 13:00-14:00, 15:00-16:00, 17:00-18:00",
|
||||
"id": "dc49a1b6-1c1f-44d6-bc52-b757aeba7b5b",
|
||||
"title": "B班",
|
||||
"date": "2024-10-05T01:31:00Z",
|
||||
"course_id": "29ab193d-2927-459d-9277-5520771b2dd6"
|
||||
},
|
||||
{
|
||||
"info2": "Room B, Sheung Shui Village, N.T.",
|
||||
"info1": "11:00-12:00, 13:00-14:00, 15:00-16:00, 17:00-18:00",
|
||||
"id": "d4785a90-311b-4a91-8fb7-beb077245f4f",
|
||||
"title": "A班",
|
||||
"date": "2024-10-06T01:31:00Z",
|
||||
"course_id": "29ab193d-2927-459d-9277-5520771b2dd6"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"yearAndMonth": "2024年11月",
|
||||
"schedule": [
|
||||
{
|
||||
"info2": "Room B, Sheung Shui Village, N.T.",
|
||||
"info1": "11:00-12:00, 13:00-14:00, 15:00-16:00, 17:00-18:00",
|
||||
"id": "5c88b2a7-6b4d-455f-b341-1fec3173d208",
|
||||
"title": "A班",
|
||||
"date": "2024-11-06T01:31:00Z",
|
||||
"course_id": "29ab193d-2927-459d-9277-5520771b2dd6"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"yearAndMonth": "2025年01月",
|
||||
"schedule": [
|
||||
{
|
||||
"info2": "Room B, Sheung Shui Village, N.T.",
|
||||
"info1": "11:00-12:00, 13:00-14:00, 15:00-16:00, 17:00-18:00",
|
||||
"id": "8a30dec2-63ed-4237-8f5b-177c42f29dda",
|
||||
"title": "B班",
|
||||
"date": "2025-01-04T01:31:00Z",
|
||||
"course_id": "29ab193d-2927-459d-9277-5520771b2dd6"
|
||||
},
|
||||
{
|
||||
"info2": "Room B, Sheung Shui Village, N.T.",
|
||||
"info1": "11:00-12:00, 13:00-14:00, 15:00-16:00, 17:00-18:00",
|
||||
"id": "86ddf906-499b-4dbd-967d-cc4dddd9f27b",
|
||||
"title": "A班",
|
||||
"date": "2025-01-05T01:31:00Z",
|
||||
"course_id": "29ab193d-2927-459d-9277-5520771b2dd6"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
console.log(newSchedule)
|
||||
return (
|
||||
<div className='relative flex flex-col w-full h-auto items-center pb-60'>
|
||||
<Collapse title='課程資訊' children={courseData.information} />
|
||||
@@ -109,7 +43,7 @@ const Accordion = async ({ courseData }: { courseData: CoursesProps }) => {
|
||||
{"課程時間表"}
|
||||
</p>
|
||||
{
|
||||
fakeData.map((item, index) => {
|
||||
newSchedule.map((item, index) => {
|
||||
return (
|
||||
<ScheduleCollapse key={index} title={item.yearAndMonth} rerganizedSchedule={{ yearAndMonth: item.yearAndMonth, schedules: item.schedule }} />
|
||||
)
|
||||
|
@@ -1,18 +1,47 @@
|
||||
import React from 'react'
|
||||
"use client"
|
||||
import React, { useEffect, useState, lazy, Suspense } from 'react'
|
||||
import Banner from './Banner'
|
||||
import LongDesc from './LongDesc'
|
||||
import CourseImagesSilder from './CourseImagesSilder'
|
||||
import Accordion from './Accordion'
|
||||
import { CoursesProps } from '@/types'
|
||||
import { CoursesProps, SettingsProps } from '@/types'
|
||||
import Footer from '../Footer'
|
||||
const Course = ({ course }: { course: CoursesProps }) => {
|
||||
import Loading from '../Loading'
|
||||
|
||||
const Course = ({ course, settings }: { course: CoursesProps, settings: SettingsProps }) => {
|
||||
|
||||
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-[#F6E8E8]'>
|
||||
<Banner courseData={course} />
|
||||
<LongDesc courseData={course} />
|
||||
<CourseImagesSilder courseData={course} />
|
||||
<Accordion courseData={course} />
|
||||
<Footer />
|
||||
{loading ? (
|
||||
<div className="flex justify-center items-center h-screen">
|
||||
<Suspense fallback={<div>Loading...</div>}>
|
||||
<Loading />
|
||||
</Suspense>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<Banner courseData={course} />
|
||||
<LongDesc courseData={course} />
|
||||
<CourseImagesSilder courseData={course} />
|
||||
<Accordion courseData={course} />
|
||||
<Footer settings={settings} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@@ -67,7 +67,7 @@ const MobileNav = ({ closeNav, showNav, courses }: Props) => {
|
||||
</div>
|
||||
|
||||
<div className='w-full h-16 flex justify-start items-center border-b-[1.5px] border-[#F5DADF]'>
|
||||
<Link key={"03"} href={"#"} >
|
||||
<Link key={"03"} href="/aboutus" >
|
||||
<p className="text-xl ml-6 text-black">
|
||||
關於我們
|
||||
</p>
|
||||
|
@@ -81,7 +81,7 @@ const Nav = ({ openNav, courses, showNav, settings }: Props) => {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<Link key={"03"} href={"#"} >
|
||||
<Link key={"03"} href="/aboutus" >
|
||||
<p className="nav__link">
|
||||
{"關於我們"}
|
||||
</p>
|
||||
@@ -93,7 +93,7 @@ const Nav = ({ openNav, courses, showNav, settings }: Props) => {
|
||||
<div className="flex items-center space-x-5 ">
|
||||
<div className="flex items-center space-x-2 max-sm:hidden">
|
||||
<div className="bg-[#DCCECF] rounded-full h-8 w-8 flex items-center justify-center hover:bg-mainColor"
|
||||
onClick={() => window.open(settings.facebook)} >
|
||||
onClick={() => window.open(settings.facebook)} >
|
||||
<FaFacebookF
|
||||
className="w-4 h-4 cursor-pointer text-[#F6E5E9]"
|
||||
/>
|
||||
|
Reference in New Issue
Block a user