From c98ccd1fa1c2b45cf5c5026094de845872ec500f Mon Sep 17 00:00:00 2001 From: Le Nhut Huy Date: Thu, 5 Feb 2026 00:04:28 +0700 Subject: [PATCH 1/2] styling ui header menu --- app/components/layout/Header/Header.tsx | 35 ++++++- app/components/layout/Header/HeaderBottom.tsx | 52 +++-------- app/components/layout/Header/Offcanvas.tsx | 7 +- app/components/layout/Header/header.json | 92 +------------------ lib/axios.ts | 20 ++++ public/assets/css/main.css | 1 + services/header-menu.service.ts | 20 ++++ types/header-menu.ts | 7 ++ 8 files changed, 99 insertions(+), 135 deletions(-) create mode 100644 lib/axios.ts create mode 100644 services/header-menu.service.ts create mode 100644 types/header-menu.ts diff --git a/app/components/layout/Header/Header.tsx b/app/components/layout/Header/Header.tsx index 6ec07fa..7b724e1 100644 --- a/app/components/layout/Header/Header.tsx +++ b/app/components/layout/Header/Header.tsx @@ -1,28 +1,61 @@ 'use client'; -import { useState } from 'react'; +import { useEffect, useState, useCallback } from 'react'; import HeaderTop from './HeaderTop'; import HeaderBottom from './HeaderBottom'; import Offcanvas from './Offcanvas'; +import { headerMenuService } from '@/services/header-menu.service'; +import { HeaderMenu as HeaderMenuType } from '@/types/header-menu'; const Header = () => { const [isOffcanvasOpen, setIsOffcanvasOpen] = useState(false); const [isSearchOpen, setIsSearchOpen] = useState(false); + const [menuItems, setMenuItems] = useState([]); + const [isLoading, setIsLoading] = useState(true); const toggleOffcanvas = () => setIsOffcanvasOpen(!isOffcanvasOpen); const toggleSearch = () => setIsSearchOpen(!isSearchOpen); + // Helper to adapt 'children' from API to 'submenu' for the existing components + const adaptMenu = useCallback((item: HeaderMenuType): any => ({ + label: item.title, + href: item.url, + submenu: item.children && item.children.length > 0 + ? item.children.map((child: HeaderMenuType) => adaptMenu(child)) + : undefined + }), []); + + useEffect(() => { + const fetchMenu = async () => { + try { + setIsLoading(true); + const data = await headerMenuService.getHeaderMenu(); + const mappedData = data.map(item => adaptMenu(item)); + setMenuItems(mappedData); + } catch (error) { + console.error('Error fetching menu in Header:', error); + } finally { + setIsLoading(false); + } + }; + + fetchMenu(); + }, [adaptMenu]); + return ( <> setIsOffcanvasOpen(false)} + menuItems={menuItems} /> {/* Search Popup */} diff --git a/app/components/layout/Header/HeaderBottom.tsx b/app/components/layout/Header/HeaderBottom.tsx index a401863..f00867c 100644 --- a/app/components/layout/Header/HeaderBottom.tsx +++ b/app/components/layout/Header/HeaderBottom.tsx @@ -1,52 +1,24 @@ 'use client'; +import React, { useEffect, useState } from 'react'; import Link from 'next/link'; import HeaderMenu from './HeaderMenu'; - -import headerData from './header.json'; - - - -// Map the JSON data to satisfy the HeaderMenu props interface -interface JsonMenuItem { - label: string; - href: string; - children?: JsonMenuItem[]; -} - -interface MenuItem { - label: string; - href: string; - submenu?: MenuItem[]; - megaMenuContent?: React.ReactNode; -} - -// We need to recursively map 'children' to 'submenu' -const mapMenuItems = (items: JsonMenuItem[]): MenuItem[] => { - return items.map(item => { - const newItem: MenuItem = { - label: item.label, - href: item.href, - }; - - - - if (item.children && item.children.length > 0) { - newItem.submenu = mapMenuItems(item.children); - } - - return newItem; - }); -}; - -const menuItems: MenuItem[] = mapMenuItems(headerData.menu as JsonMenuItem[]); +import { headerMenuService } from '@/services/header-menu.service'; +import { HeaderMenu as HeaderMenuType } from '@/types/header-menu'; interface HeaderBottomProps { onToggleOffcanvas: () => void; onToggleSearch: () => void; + menuItems: any[]; + isLoading: boolean; } -const HeaderBottom: React.FC = ({ onToggleOffcanvas, onToggleSearch }) => { +const HeaderBottom: React.FC = ({ + onToggleOffcanvas, + onToggleSearch, + menuItems, + isLoading +}) => { return (
@@ -59,7 +31,7 @@ const HeaderBottom: React.FC = ({ onToggleOffcanvas, onToggle
- + {!isLoading && }
diff --git a/app/components/layout/Header/Offcanvas.tsx b/app/components/layout/Header/Offcanvas.tsx index e1d0bd2..b03ed6e 100644 --- a/app/components/layout/Header/Offcanvas.tsx +++ b/app/components/layout/Header/Offcanvas.tsx @@ -20,9 +20,10 @@ interface MenuItem { interface OffcanvasProps { isOpen: boolean; onClose: () => void; + menuItems: any[]; } -const Offcanvas: React.FC = ({ isOpen, onClose }) => { +const Offcanvas: React.FC = ({ isOpen, onClose, menuItems }) => { // Explicitly casting headerData to the expected structure const data = headerData as { top: { @@ -37,10 +38,10 @@ const Offcanvas: React.FC = ({ isOpen, onClose }) => { phone: string; }; }; - menu: MenuItem[]; }; - const { offcanvas, top, menu } = data; + const { offcanvas, top } = data; + const menu = menuItems; return ( <> diff --git a/app/components/layout/Header/header.json b/app/components/layout/Header/header.json index cf55fb5..ae91152 100644 --- a/app/components/layout/Header/header.json +++ b/app/components/layout/Header/header.json @@ -48,95 +48,5 @@ "workingHours": "Mod-Friday, 09am - 05pm", "phone": "+09 378 357 5222" } - }, - "menu": [ - { - "label": "Home", - "href": "/", - "children": [] - }, - { - "label": "About Us", - "href": "/about", - "children": [] - }, - { - "label": "Pages", - "href": "#", - "children": [ - { - "label": "Service", - "href": "/service", - "children": [ - { - "label": "Service", - "href": "/service" - }, - { - "label": "Service Details", - "href": "/service-details" - } - ] - }, - { - "label": "Country List", - "href": "/country-list", - "children": [ - { - "label": "Country List", - "href": "/country-list" - }, - { - "label": "Country Details", - "href": "/country-details" - } - ] - }, - { - "label": "Our Pricing", - "href": "/pricing" - }, - { - "label": "Appointment", - "href": "/appointment" - } - ] - }, - { - "label": "VISA", - "href": "#", - "children": [ - { - "label": "Visa List", - "href": "/visa-list" - }, - { - "label": "Visa Details", - "href": "/visa-details" - } - ] - }, - { - "label": "Blog", - "href": "#", - "children": [ - { - "label": "Blog Grid", - "href": "/blog-grid" - }, - { - "label": "Blog Standard", - "href": "/blog" - }, - { - "label": "Blog Details", - "href": "/blog-details" - } - ] - }, - { - "label": "Contact Us", - "href": "/contact" - } - ] + } } diff --git a/lib/axios.ts b/lib/axios.ts new file mode 100644 index 0000000..66d7f04 --- /dev/null +++ b/lib/axios.ts @@ -0,0 +1,20 @@ +import axios from 'axios'; + +const axiosInstance = axios.create({ + baseURL: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001', + timeout: 10000, + headers: { + 'Content-Type': 'application/json', + }, +}); + +// Response interceptor for basic error handling +axiosInstance.interceptors.response.use( + (response) => response, + (error) => { + console.error('API Error:', error.response?.data || error.message); + return Promise.reject(error); + } +); + +export default axiosInstance; diff --git a/public/assets/css/main.css b/public/assets/css/main.css index 55e5e10..4c1bea0 100644 --- a/public/assets/css/main.css +++ b/public/assets/css/main.css @@ -9499,3 +9499,4 @@ html.lenis body { a { color: var(--white); } /*# sourceMappingURL=main.css.map */ + diff --git a/services/header-menu.service.ts b/services/header-menu.service.ts new file mode 100644 index 0000000..8b9b4c8 --- /dev/null +++ b/services/header-menu.service.ts @@ -0,0 +1,20 @@ +import axiosInstance from '../lib/axios'; +import { HeaderMenu } from '../types/header-menu'; + +export const headerMenuService = { + /** + * Fetch active header menu tree from API + */ + async getHeaderMenu(): Promise { + try { + const response = await axiosInstance.get<{ success: boolean; data: HeaderMenu[] }>('/api/header-menu'); + if (response.data.success) { + return response.data.data; + } + return []; + } catch (error) { + console.error('Failed to fetch header menu:', error); + return []; // Fallback to empty menu + } + } +}; diff --git a/types/header-menu.ts b/types/header-menu.ts new file mode 100644 index 0000000..f65352b --- /dev/null +++ b/types/header-menu.ts @@ -0,0 +1,7 @@ +export interface HeaderMenu { + id: string; + title: string; + url: string; + type?: 'internal' | 'external'; + children?: HeaderMenu[]; +} From 0b2e3d21235fa73ece00134eef9e1c52a260b00c Mon Sep 17 00:00:00 2001 From: r2xrzh9q2z-lab Date: Thu, 5 Feb 2026 05:55:00 +0700 Subject: [PATCH 2/2] Update UI, Call API --- api/visa.ts | 831 +++++++++++++++++++++++ app/components/layout/Header/header.json | 2 +- app/layout.tsx | 45 +- app/visa/[slug]/Countrydetails.tsx | 416 ------------ app/visa/[slug]/VisaDetail.tsx | 233 +++++++ app/visa/[slug]/page.tsx | 283 +------- app/visa/components/Breadcrumb.tsx | 4 +- app/visa/layout.tsx | 387 ----------- app/visa/page.tsx | 133 ++-- app/visa/visa.json | 541 +++++++-------- 10 files changed, 1489 insertions(+), 1386 deletions(-) create mode 100644 api/visa.ts delete mode 100644 app/visa/[slug]/Countrydetails.tsx create mode 100644 app/visa/[slug]/VisaDetail.tsx diff --git a/api/visa.ts b/api/visa.ts new file mode 100644 index 0000000..0a6f9e4 --- /dev/null +++ b/api/visa.ts @@ -0,0 +1,831 @@ +// app/api/visa/route.ts + +import { NextRequest, NextResponse } from "next/server"; + +// ==================== INTERFACES ==================== + +interface VisaItem { + title: string; + description: string; +} + +interface VisaTypeCategory { + items: VisaItem[]; +} + +interface VisaProcessStep { + number: string; + title: string; + description: string; +} + +interface VisaProcess { + title: string; + steps: VisaProcessStep[]; +} + +interface VisaCategory { + title: string; + steps: string[][]; +} + +interface VisaService { + title: string; + steps: VisaProcessStep[]; +} + +interface RelatedCountry { + id: number; + name: string; + icon: string; +} + +interface ContactInfo { + sectionTitle: string; + helpText: string; + img: string; + phone: { + label: string; + value: string; + link: string; + }; + email: { + label: string; + value: string; + link: string; + }; + location: { + label: string; + address: string; + }; +} + +interface ActiveCountry { + id: number; + name: string; + title: string; + mainImage: string; + description: string; + additionalInfo: string; + tagline: string; + visaTypes: VisaTypeCategory[]; + visaProcess: VisaProcess; + gallery: string[]; + visaCategories: VisaCategory; + visaService: VisaService; +} + +export interface DetailedView { + activeCountry: ActiveCountry; + relatedCountries: RelatedCountry[]; + contactInfo: ContactInfo; +} + +export interface VisaCountry { + id: number; + name: string; + slug: string; + icon: string; + services: string[]; + detailedView?: DetailedView; +} + +export interface VisaHero { + title: string; + summaryList: VisaCountry[]; +} + +export interface VisaData { + hero: VisaHero; +} + +export interface VisaApiResponse { + success: boolean; + message?: string; + data?: VisaCountry | VisaCountry[] | VisaHero | null; + error?: string; +} + +export interface VisaInquiry { + name: string; + email: string; + phone: string; + country: string; + visaType: string; +} + +export interface VisaInquiryResponse { + success: boolean; + message: string; + inquiryId?: string; + data?: VisaInquiry; +} + +// ==================== HELPER FUNCTIONS ==================== + +const getApiUrl = (): string => { + return process.env.NEXT_PUBLIC_API_URL || "http://localhost:3001"; +}; + +/** + * Fetch visa data từ remote API hoặc fallback + * @param slug - Optional country slug + * @returns Promise + */ +export async function fetchVisaData(): Promise { + const apiUrl = getApiUrl(); + const url = `${apiUrl}`; // Đảm bảo apiUrl không thừa dấu / ở cuối + + try { + const response = await fetch(`${url}/api/visa`, { + method: "GET", + headers: { "Content-Type": "application/json" }, + cache: "no-store", + }); + + if (!response.ok) throw new Error(`API returned ${response.status}`); + + const apiResponse = await response.json(); + + if (!apiResponse.success || !apiResponse.hero) { + throw new Error("Dữ liệu API không đúng cấu trúc"); + } + + // Hàm bổ trợ để nối URL chuẩn + const fixUrl = (path: string) => { + if (!path || path.startsWith("http")) return path; + return `${url}${path.startsWith("/") ? "" : "/"}${path}`; + }; + + // Duyệt qua danh sách summaryList để ghi đè toàn bộ ảnh + if (apiResponse.hero.summaryList) { + apiResponse.hero.summaryList = apiResponse.hero.summaryList.map( + (country: any) => { + // 1. Fix icon cấp gốc + const updatedCountry = { + ...country, + icon: fixUrl(country.icon), + }; + + // 2. Fix sâu trong detailedView (nếu có) + if (updatedCountry.detailedView) { + const dv = updatedCountry.detailedView; + + updatedCountry.detailedView = { + ...dv, + // Fix ảnh trong activeCountry + activeCountry: dv.activeCountry + ? { + ...dv.activeCountry, + mainImage: fixUrl(dv.activeCountry.mainImage), + gallery: dv.activeCountry.gallery?.map(fixUrl), + } + : dv.activeCountry, + + // Fix icon trong danh sách nước liên quan + relatedCountries: dv.relatedCountries?.map((rc: any) => ({ + ...rc, + icon: fixUrl(rc.icon), + })), + + // Fix ảnh nền trong contactInfo + contactInfo: dv.contactInfo + ? { + ...dv.contactInfo, + img: fixUrl(dv.contactInfo.img), + } + : dv.contactInfo, + }; + } + + return updatedCountry; + }, + ); + } + + return apiResponse; + } catch (error) { + console.error("❌ Error fetching:", error); + return getFallbackVisaData(); + } +} +// ==================== FALLBACK DATA ==================== + +/** + * Fallback visa data - được dùng khi API không hoạt động + */ +function getFallbackVisaData(): VisaData { + return { + hero: { + title: "Visa Services ", + summaryList: [ + { + id: 1, + name: "France", + slug: "france", + icon: "/assets/img/home-2/visa/03.png", + services: [ + "Student Visa & Admission", + "Work Visa – H1B", + "Work permit for Canada", + "Student Visa for Canada", + ], + detailedView: { + activeCountry: { + id: 1, + name: "France", + title: "COUNTRY FRANCE", + mainImage: "/assets/img/inner-page/country-details/details-1.jpg", + description: + "France is one of the most popular destinations for international students, offering world-class universities, diverse cultural experiences, and countless career opportunities...", + additionalInfo: + "Our consultancy provides complete guidance for study visas, work permits, and permanent residency pathways tailored to your goals.", + tagline: + "Over the last 35 Years we made an impact that is strong & we have long way to go.", + visaTypes: [ + { + items: [ + { + title: "Tourist Visa", + description: + "Broad term that can refer to various aspects of interconnectedness", + }, + { + title: "Work Permit", + description: + "Broad term that can refer to various aspects of interconnectedness", + }, + ], + }, + { + items: [ + { + title: "Student", + description: + "Broad term that can refer to various aspects of interconnectedness", + }, + { + title: "Family Visa", + description: + "Broad term that can refer to various aspects of interconnectedness", + }, + ], + }, + ], + visaProcess: { + title: "France Visa Process", + steps: [ + { + number: "01", + title: "Consultation & Eligibility Check", + description: + "Our experts review your profile and visa requirements.", + }, + { + number: "02", + title: "Application Preparation", + description: + "We help with document collection, form filling, and statement drafting.", + }, + { + number: "03", + title: "Submission", + description: + "Visa application is submitted online with required fees.", + }, + { + number: "04", + title: "Interview Guidance", + description: + "Get training and mock sessions for embassy interview.", + }, + { + number: "05", + title: "Approval & Travel", + description: + "Once approved, we provide travel and pre-departure guidance.", + }, + ], + }, + gallery: [ + "/assets/img/inner-page/country-details/details-2.jpg", + "/assets/img/inner-page/country-details/details-3.png", + ], + visaCategories: { + title: "Types of France Visas", + steps: [ + [ + "Student Visa (F1, M1, J1)", + "Work Visa (H1B, L1)", + "Tourist Visa (B1/B2)", + ], + [ + "Family/Spouse Visa (K1, IR1, F2A)", + "Green Card / Immigrant Visa", + ], + ], + }, + visaService: { + title: "Our France Visa Service Options", + steps: [ + { + number: "01", + title: "Consultation & Eligibility Check", + description: + "Our experts review your profile and visa requirements.", + }, + { + number: "02", + title: "Application Preparation", + description: + "We help with document collection, form filling, and statement drafting.", + }, + { + number: "03", + title: "Submission", + description: + "Visa application is submitted online with required fees.", + }, + { + number: "04", + title: "Interview Guidance", + description: + "Get training and mock sessions for embassy interview.", + }, + { + number: "05", + title: "Approval & Travel", + description: + "Once approved, we provide travel and pre-departure guidance.", + }, + ], + }, + }, + relatedCountries: [ + { + id: 1, + name: "Canada", + icon: "/assets/img/inner-page/country-details/01.png", + }, + { + id: 2, + name: "USA", + icon: "/assets/img/inner-page/country-details/02.png", + }, + { + id: 3, + name: "UK", + icon: "/assets/img/inner-page/country-details/03.png", + }, + { + id: 4, + name: "Germany", + icon: "/assets/img/inner-page/country-details/05.png", + }, + { + id: 5, + name: "Spain", + icon: "/assets/img/inner-page/country-details/06.png", + }, + ], + contactInfo: { + sectionTitle: "Visa & Immigration", + helpText: "Need Help? Book Lab Visit", + img: "/assets/img/inner-page/country-details/bg.jpg", + phone: { + label: "Call Us", + value: "+33 1 23 45 67 89", + link: "tel:+33123456789", + }, + email: { + label: "Mail Us", + value: "visa@france-consultant.com", + link: "mailto:visa@france-consultant.com", + }, + location: { + label: "Location", + address: "Paris, Lyon, Marseille", + }, + }, + }, + }, + { + id: 2, + name: "UK", + slug: "uk", + icon: "/assets/img/home-2/visa/11.png", + services: [ + "Student Visa & Admission", + "Work Visa – Skilled Worker", + "Family Visa", + "Entrepreneur Visa", + ], + detailedView: { + activeCountry: { + id: 2, + name: "United Kingdom", + title: "COUNTRY UK", + mainImage: "/assets/img/inner-page/country-details/details-1.jpg", + description: + "The UK is a world leader in education and innovation, offering exceptional universities and career opportunities for international professionals...", + additionalInfo: + "We provide comprehensive support for UK student visas, work visas, and family sponsorship applications.", + tagline: "35+ years of excellence in UK visa consulting.", + visaTypes: [ + { + category: "Student & Work", + items: [ + { + title: "Student Visa", + description: + "Study at UK universities with part-time work opportunities", + }, + { + title: "Graduate Visa", + description: + "Work in the UK after completing your studies", + }, + ], + }, + { + category: "Family & Other", + items: [ + { + title: "Skilled Worker Visa", + description: "Work in a skilled occupation in the UK", + }, + { + title: "Family Visa", + description: "Join your family in the UK", + }, + ], + }, + ], + visaProcess: { + title: "UK Visa Process", + steps: [ + { + number: "01", + title: "Eligibility Assessment", + description: + "We evaluate your qualifications and circumstances.", + }, + { + number: "02", + title: "Documentation", + description: + "Comprehensive document preparation and review.", + }, + { + number: "03", + title: "Application Submission", + description: "Submit your visa application online.", + }, + { + number: "04", + title: "Biometrics & Interview", + description: "Complete biometric appointment if required.", + }, + { + number: "05", + title: "Visa Decision", + description: "Receive your visa and start your UK journey.", + }, + ], + }, + gallery: [ + "/assets/img/inner-page/country-details/details-2.jpg", + "/assets/img/inner-page/country-details/details-3.png", + ], + visaCategories: { + title: "Types of UK Visas", + steps: [ + [ + "Student Visa (Tier 4)", + "Graduate Visa", + "Skilled Worker Visa", + ], + ["Family Visa", "Visitor Visa", "Entrepreneur Visa"], + ], + }, + visaService: { + title: "Our UK Visa Services", + steps: [ + { + number: "01", + title: "Initial Consultation", + description: "Free assessment of your visa eligibility.", + }, + { + number: "02", + title: "Document Preparation", + description: "Expert guidance on all required documents.", + }, + { + number: "03", + title: "Application Submission", + description: "Professional submission and tracking.", + }, + { + number: "04", + title: "Interview Coaching", + description: "Prepare for your visa interview.", + }, + { + number: "05", + title: "Post-Visa Support", + description: "Guidance for accommodation and settlement.", + }, + ], + }, + }, + relatedCountries: [ + { + id: 1, + name: "Canada", + icon: "/assets/img/inner-page/country-details/01.png", + }, + { + id: 2, + name: "USA", + icon: "/assets/img/inner-page/country-details/02.png", + }, + { + id: 3, + name: "Australia", + icon: "/assets/img/inner-page/country-details/03.png", + }, + ], + contactInfo: { + sectionTitle: "UK Visa & Immigration", + helpText: "Need Help? Book Consultation", + img: "/assets/img/inner-page/country-details/bg.jpg", + phone: { + label: "Call Us", + value: "+44 20 7946 0958", + link: "tel:+442079460958", + }, + email: { + label: "Mail Us", + value: "visa@uk-consultant.com", + link: "mailto:visa@uk-consultant.com", + }, + location: { + label: "Location", + address: "London, Manchester, Birmingham", + }, + }, + }, + }, + { + id: 3, + name: "Canada", + slug: "canada", + icon: "/assets/img/home-2/visa/02.png", + services: [ + "Student Visa & Admission", + "Work Permit", + "Express Entry", + "Family Sponsorship", + ], + detailedView: { + activeCountry: { + id: 3, + name: "Canada", + title: "COUNTRY CANADA", + mainImage: "/assets/img/inner-page/country-details/details-1.jpg", + description: + "Canada is known for its high quality of life, excellent education system, and welcoming immigration policies...", + additionalInfo: + "We specialize in Express Entry, study permits, and work permits for Canada.", + tagline: "Your pathway to a better life in Canada starts here.", + visaTypes: [ + { + category: "Study & Work", + items: [ + { + title: "Study Permit", + description: "Study at Canadian institutions", + }, + { + title: "Work Permit", + description: "Temporary work in Canada", + }, + ], + }, + { + category: "Immigration & Family", + items: [ + { + title: "Express Entry", + description: "Fast-track permanent residency", + }, + { + title: "Family Sponsorship", + description: "Bring your family to Canada", + }, + ], + }, + ], + visaProcess: { + title: "Canada Visa Process", + steps: [ + { + number: "01", + title: "Initial Assessment", + description: + "We assess your eligibility for Canadian programs.", + }, + { + number: "02", + title: "Documentation", + description: "Prepare comprehensive application packages.", + }, + { + number: "03", + title: "Application", + description: "Submit to IRCC (Immigration Canada).", + }, + { + number: "04", + title: "Medical & Security", + description: "Complete medical exams and security checks.", + }, + { + number: "05", + title: "Approval", + description: "Receive your visa and prepare for arrival.", + }, + ], + }, + gallery: [ + "/assets/img/inner-page/country-details/details-2.jpg", + "/assets/img/inner-page/country-details/details-3.png", + ], + visaCategories: { + title: "Types of Canadian Visas", + steps: [ + [ + "Study Permit", + "Work Permit (Open/Closed)", + "International Mobility Program", + ], + [ + "Express Entry (FSW, CEC, FST)", + "Provincial Nominee Program", + "Family Sponsorship", + ], + ], + }, + visaService: { + title: "Our Canada Visa Services", + steps: [ + { + number: "01", + title: "Free Consultation", + description: "Discuss your Canadian immigration goals.", + }, + { + number: "02", + title: "Eligibility Check", + description: "Determine best pathway for you.", + }, + { + number: "03", + title: "Application Support", + description: "Complete assistance with applications.", + }, + { + number: "04", + title: "Preparation", + description: "Prepare for medical exams and interviews.", + }, + { + number: "05", + title: "Settlement Support", + description: "Help with housing and job search.", + }, + ], + }, + }, + relatedCountries: [ + { + id: 1, + name: "USA", + icon: "/assets/img/inner-page/country-details/01.png", + }, + { + id: 2, + name: "Australia", + icon: "/assets/img/inner-page/country-details/02.png", + }, + ], + contactInfo: { + sectionTitle: "Canada Visa & Immigration", + helpText: "Ready to Immigrate to Canada?", + img: "/assets/img/inner-page/country-details/bg.jpg", + phone: { + label: "Call Us", + value: "+1 416 815 7755", + link: "tel:+14168157755", + }, + email: { + label: "Mail Us", + value: "visa@canada-consultant.com", + link: "mailto:visa@canada-consultant.com", + }, + location: { + label: "Location", + address: "Toronto, Vancouver, Montreal", + }, + }, + }, + }, + { + id: 4, + name: "Germany", + slug: "germany", + icon: "/assets/img/home-2/visa/12.png", + services: [ + "Student Visa & Admission", + "Work Visa – H1B", + "Work permit for Canada", + "Student Visa for Canada", + ], + }, + { + id: 5, + name: "Spain", + slug: "spain", + icon: "/assets/img/home-2/visa/13.png", + services: [ + "Student Visa & Admission", + "Work Visa – H1B", + "Work permit for Canada", + "Student Visa for Canada", + ], + }, + { + id: 6, + name: "South Korea", + slug: "south-korea", + icon: "/assets/img/home-2/visa/14.png", + services: [ + "Student Visa & Admission", + "Work Visa – H1B", + "Work permit for Canada", + "Student Visa for Canada", + ], + }, + { + id: 7, + name: "Japan", + slug: "japan", + icon: "/assets/img/home-2/visa/15.png", + services: [ + "Student Visa & Admission", + "Work Visa – H1B", + "Work permit for Canada", + "Student Visa for Canada", + ], + }, + { + id: 8, + name: "Croatia", + slug: "croatia", + icon: "/assets/img/home-2/visa/16.png", + services: [ + "Student Visa & Admission", + "Work Visa – H1B", + "Work permit for Canada", + "Student Visa for Canada", + ], + }, + { + id: 9, + name: "England", + slug: "england", + icon: "/assets/img/home-2/visa/17.png", + services: [ + "Student Visa & Admission", + "Work Visa – H1B", + "Work permit for Canada", + "Student Visa for Canada", + ], + }, + { + id: 10, + name: "Indonesia", + slug: "indonesia", + icon: "/assets/img/home-2/visa/18.png", + services: [ + "Student Visa & Admission", + "Work Visa – H1B", + "Work permit for Canada", + "Student Visa for Canada", + ], + }, + ], + }, + }; +} diff --git a/app/components/layout/Header/header.json b/app/components/layout/Header/header.json index 8363255..db125f6 100644 --- a/app/components/layout/Header/header.json +++ b/app/components/layout/Header/header.json @@ -108,7 +108,7 @@ "children": [ { "label": "Visa List", - "href": "/visa-list" + "href": "/visa" }, { "label": "Visa Details", diff --git a/app/layout.tsx b/app/layout.tsx index 7e73f2b..c1bbf86 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -43,19 +43,46 @@ export default function RootLayout({ {children}