forked from UKSOURCE/hailearning.edu.vn
Update UI, Call API
This commit is contained in:
831
api/visa.ts
Normal file
831
api/visa.ts
Normal file
@@ -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<VisaCountry | VisaCountry[]>
|
||||||
|
*/
|
||||||
|
export async function fetchVisaData(): Promise<any> {
|
||||||
|
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",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -108,7 +108,7 @@
|
|||||||
"children": [
|
"children": [
|
||||||
{
|
{
|
||||||
"label": "Visa List",
|
"label": "Visa List",
|
||||||
"href": "/visa-list"
|
"href": "/visa"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "Visa Details",
|
"label": "Visa Details",
|
||||||
|
|||||||
@@ -43,19 +43,46 @@ export default function RootLayout({
|
|||||||
{children}
|
{children}
|
||||||
<Footer />
|
<Footer />
|
||||||
|
|
||||||
<Script src="/assets/js/jquery-3.7.1.min.js" strategy="beforeInteractive" />
|
<Script
|
||||||
<Script src="/assets/js/viewport.jquery.js" strategy="afterInteractive" />
|
src="/assets/js/jquery-3.7.1.min.js"
|
||||||
<Script src="/assets/js/bootstrap.bundle.min.js" strategy="afterInteractive" />
|
strategy="beforeInteractive"
|
||||||
<Script src="/assets/js/jquery.nice-select.min.js" strategy="afterInteractive" />
|
/>
|
||||||
<Script src="/assets/js/jquery.waypoints.js" strategy="afterInteractive" />
|
<Script
|
||||||
|
src="/assets/js/viewport.jquery.js"
|
||||||
|
strategy="afterInteractive"
|
||||||
|
/>
|
||||||
|
<Script
|
||||||
|
src="/assets/js/bootstrap.bundle.min.js"
|
||||||
|
strategy="afterInteractive"
|
||||||
|
/>
|
||||||
|
<Script
|
||||||
|
src="/assets/js/jquery.nice-select.min.js"
|
||||||
|
strategy="afterInteractive"
|
||||||
|
/>
|
||||||
|
<Script
|
||||||
|
src="/assets/js/jquery.waypoints.js"
|
||||||
|
strategy="afterInteractive"
|
||||||
|
/>
|
||||||
<Script src="/assets/js/odometer.min.js" strategy="afterInteractive" />
|
<Script src="/assets/js/odometer.min.js" strategy="afterInteractive" />
|
||||||
<Script src="/assets/js/swiper-bundle.min.js" strategy="afterInteractive" />
|
<Script
|
||||||
<Script src="/assets/js/jquery.meanmenu.min.js" strategy="afterInteractive" />
|
src="/assets/js/swiper-bundle.min.js"
|
||||||
<Script src="/assets/js/jquery.magnific-popup.min.js" strategy="afterInteractive" />
|
strategy="afterInteractive"
|
||||||
|
/>
|
||||||
|
<Script
|
||||||
|
src="/assets/js/jquery.meanmenu.min.js"
|
||||||
|
strategy="afterInteractive"
|
||||||
|
/>
|
||||||
|
<Script
|
||||||
|
src="/assets/js/jquery.magnific-popup.min.js"
|
||||||
|
strategy="afterInteractive"
|
||||||
|
/>
|
||||||
<Script src="/assets/js/wow.min.js" strategy="afterInteractive" />
|
<Script src="/assets/js/wow.min.js" strategy="afterInteractive" />
|
||||||
<Script src="/assets/js/gsap.js" strategy="afterInteractive" />
|
<Script src="/assets/js/gsap.js" strategy="afterInteractive" />
|
||||||
<Script src="/assets/js/lenis.min.js" strategy="afterInteractive" />
|
<Script src="/assets/js/lenis.min.js" strategy="afterInteractive" />
|
||||||
<Script src="/assets/js/ScrollTrigger.min.js" strategy="afterInteractive" />
|
<Script
|
||||||
|
src="/assets/js/ScrollTrigger.min.js"
|
||||||
|
strategy="afterInteractive"
|
||||||
|
/>
|
||||||
<Script src="/assets/js/SplitText.min.js" strategy="afterInteractive" />
|
<Script src="/assets/js/SplitText.min.js" strategy="afterInteractive" />
|
||||||
<Script src="/assets/js/main.js" strategy="afterInteractive" />
|
<Script src="/assets/js/main.js" strategy="afterInteractive" />
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,416 +0,0 @@
|
|||||||
"use client";
|
|
||||||
|
|
||||||
import React, { useState, useEffect } from "react";
|
|
||||||
import Link from "next/link";
|
|
||||||
import visaData from "../visa.json";
|
|
||||||
|
|
||||||
const ASSET_URL = process.env.NEXT_PUBLIC_API_URL || "";
|
|
||||||
|
|
||||||
interface CountryDetailsClientProps {
|
|
||||||
country: {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
icon: string;
|
|
||||||
services: string[];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function CountryDetailsClient({
|
|
||||||
country,
|
|
||||||
}: CountryDetailsClientProps) {
|
|
||||||
const [showBackToTop, setShowBackToTop] = useState(false);
|
|
||||||
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
|
||||||
|
|
||||||
// Get detailed data from visa.json
|
|
||||||
const countryData = visaData.visaSystem.detailedView.activeCountry;
|
|
||||||
const relatedCountries =
|
|
||||||
visaData.visaSystem.detailedView.relatedCountries.map((c: any) => ({
|
|
||||||
...c,
|
|
||||||
icon: `${ASSET_URL}/${c.icon}`,
|
|
||||||
}));
|
|
||||||
const contactInfo = visaData.visaSystem.contactInfo;
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const handleScroll = () => setShowBackToTop(window.scrollY > 100);
|
|
||||||
window.addEventListener("scroll", handleScroll);
|
|
||||||
return () => window.removeEventListener("scroll", handleScroll);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const scrollToTop = () => window.scrollTo({ top: 0, behavior: "smooth" });
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{/* Back to Top */}
|
|
||||||
<button
|
|
||||||
onClick={scrollToTop}
|
|
||||||
className={`fixed bottom-8 right-8 w-12 h-12 rounded-full bg-white shadow-lg flex items-center justify-center cursor-pointer transition-all z-40 ${
|
|
||||||
showBackToTop ? "opacity-100" : "opacity-0 pointer-events-none"
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
className="w-6 h-6 text-blue-600"
|
|
||||||
fill="none"
|
|
||||||
stroke="currentColor"
|
|
||||||
viewBox="0 0 24 24"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
strokeLinecap="round"
|
|
||||||
strokeLinejoin="round"
|
|
||||||
strokeWidth={2}
|
|
||||||
d="M7 11l5-5m0 0l5 5m-5-5v12"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
{/* Header Top */}
|
|
||||||
<div className="bg-gray-900 text-white py-3 hidden lg:block">
|
|
||||||
<div className="max-w-7xl mx-auto px-8 flex justify-between items-center text-sm">
|
|
||||||
<ul className="flex gap-8">
|
|
||||||
<li>
|
|
||||||
<a href="tel:+093783575222">+09 378 357 5222</a>
|
|
||||||
</li>
|
|
||||||
<li>69 Street, 5th Avenue LA, United States</li>
|
|
||||||
<li>
|
|
||||||
<a href="mailto:info@example.com">info@example.com</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<select className="bg-gray-900 text-white border-0 outline-none cursor-pointer">
|
|
||||||
<option>English</option>
|
|
||||||
<option>Bangla</option>
|
|
||||||
<option>Hindi</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Header */}
|
|
||||||
<header className="sticky top-0 z-20 bg-white shadow-md">
|
|
||||||
<div className="max-w-7xl mx-auto px-4 lg:px-8 py-4 flex justify-between items-center">
|
|
||||||
<Link href="/" className="flex-shrink-0">
|
|
||||||
<img
|
|
||||||
src={`${ASSET_URL}/assets/img/logo/black-logo.svg`}
|
|
||||||
alt="logo"
|
|
||||||
className="h-10"
|
|
||||||
/>
|
|
||||||
</Link>
|
|
||||||
<nav className="hidden lg:flex gap-8">
|
|
||||||
<Link href="/" className="text-gray-700 hover:text-blue-600">
|
|
||||||
Home
|
|
||||||
</Link>
|
|
||||||
<Link href="/about" className="text-gray-700 hover:text-blue-600">
|
|
||||||
About Us
|
|
||||||
</Link>
|
|
||||||
<Link
|
|
||||||
href="/country-list"
|
|
||||||
className="text-gray-700 hover:text-blue-600"
|
|
||||||
>
|
|
||||||
VISA
|
|
||||||
</Link>
|
|
||||||
<Link href="/contact" className="text-gray-700 hover:text-blue-600">
|
|
||||||
Contact Us
|
|
||||||
</Link>
|
|
||||||
</nav>
|
|
||||||
<button
|
|
||||||
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
|
|
||||||
className="lg:hidden text-2xl"
|
|
||||||
>
|
|
||||||
☰
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
{/* Mobile Menu */}
|
|
||||||
{isMobileMenuOpen && (
|
|
||||||
<div className="fixed inset-0 z-30 lg:hidden">
|
|
||||||
<div
|
|
||||||
className="absolute inset-0 bg-black/50"
|
|
||||||
onClick={() => setIsMobileMenuOpen(false)}
|
|
||||||
></div>
|
|
||||||
<div className="absolute left-0 top-0 w-80 h-full bg-white p-6 overflow-y-auto">
|
|
||||||
<button
|
|
||||||
onClick={() => setIsMobileMenuOpen(false)}
|
|
||||||
className="float-right text-2xl"
|
|
||||||
>
|
|
||||||
✕
|
|
||||||
</button>
|
|
||||||
<nav className="space-y-3 mt-8">
|
|
||||||
<Link href="/" className="block py-2">
|
|
||||||
Home
|
|
||||||
</Link>
|
|
||||||
<Link href="/about" className="block py-2">
|
|
||||||
About Us
|
|
||||||
</Link>
|
|
||||||
<Link href="/country-list" className="block py-2">
|
|
||||||
Visa
|
|
||||||
</Link>
|
|
||||||
<Link href="/contact" className="block py-2">
|
|
||||||
Contact Us
|
|
||||||
</Link>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Breadcrumb */}
|
|
||||||
<section
|
|
||||||
className="py-20 px-4 lg:px-8 bg-cover relative"
|
|
||||||
style={{
|
|
||||||
backgroundImage: `url('${ASSET_URL}/${countryData.mainImage}')`,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="absolute inset-0 bg-black/30"></div>
|
|
||||||
<div className="max-w-7xl mx-auto relative z-10 text-center text-white">
|
|
||||||
<h1 className="text-5xl font-bold mb-6">{countryData.title}</h1>
|
|
||||||
<ul className="flex justify-center gap-4">
|
|
||||||
<li>
|
|
||||||
<Link href="/">Home</Link>
|
|
||||||
</li>
|
|
||||||
<li>›</li>
|
|
||||||
<li>{countryData.name}</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
{/* Country Details */}
|
|
||||||
<section className="py-20 px-4 lg:px-8">
|
|
||||||
<div className="max-w-7xl mx-auto">
|
|
||||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
|
||||||
{/* Main Content */}
|
|
||||||
<div className="lg:col-span-2">
|
|
||||||
<img
|
|
||||||
src={`${ASSET_URL}/${countryData.mainImage}`}
|
|
||||||
alt={countryData.name}
|
|
||||||
className="w-full rounded-lg mb-8"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<h2 className="text-4xl font-bold mb-4">{countryData.name}</h2>
|
|
||||||
<p className="text-gray-700 mb-4">{countryData.description}</p>
|
|
||||||
<p className="text-gray-700 mb-4">{countryData.additionalInfo}</p>
|
|
||||||
<h5 className="text-xl font-semibold mb-6">
|
|
||||||
{countryData.tagline}
|
|
||||||
</h5>
|
|
||||||
|
|
||||||
{/* Visa Types */}
|
|
||||||
<div className="grid grid-cols-2 gap-6 mb-8">
|
|
||||||
{countryData.visaTypes.map((typeGroup: any, idx: number) => (
|
|
||||||
<React.Fragment key={idx}>
|
|
||||||
{typeGroup.items.map((item: any, itemIdx: number) => (
|
|
||||||
<div
|
|
||||||
key={itemIdx}
|
|
||||||
className="p-6 border-l-4 border-blue-600"
|
|
||||||
>
|
|
||||||
<h5 className="font-bold mb-2">{item.title}</h5>
|
|
||||||
<p className="text-sm text-gray-600">
|
|
||||||
{item.description}
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</React.Fragment>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Visa Process */}
|
|
||||||
<h3 className="text-2xl font-bold mb-6">USA Visa Process</h3>
|
|
||||||
<ul className="space-y-4 mb-8">
|
|
||||||
{countryData.visaProcess.steps.map((process: any) => (
|
|
||||||
<li key={process.number} className="flex gap-4">
|
|
||||||
<span className="font-bold text-blue-600 flex-shrink-0">
|
|
||||||
{process.number}.
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
<strong>{process.title}</strong> – {process.description}
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
{/* Gallery */}
|
|
||||||
<div className="grid grid-cols-2 gap-6 mb-8">
|
|
||||||
{countryData.gallery.map((image: string, idx: number) => (
|
|
||||||
<img
|
|
||||||
key={idx}
|
|
||||||
src={`${ASSET_URL}/${image}`}
|
|
||||||
alt={`${countryData.name} gallery`}
|
|
||||||
className="rounded-lg w-full"
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Visa Types List */}
|
|
||||||
<h3 className="text-2xl font-bold mb-6">Types of Visas</h3>
|
|
||||||
{countryData.visaCategories.steps.map(
|
|
||||||
(subGroup: string[], groupIdx: number) => (
|
|
||||||
<ul className="visa-list-2" key={groupIdx}>
|
|
||||||
{/* Map lần 2 để render từng chuỗi trong mảng con */}
|
|
||||||
{subGroup.map((category: string, idx: number) => (
|
|
||||||
<li key={idx}>
|
|
||||||
<i className="fa-solid fa-chevrons-right"></i>
|
|
||||||
{category}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
),
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Service Options */}
|
|
||||||
<h3 className="text-2xl font-bold mb-6">
|
|
||||||
Our {countryData.name} Visa Service Options
|
|
||||||
</h3>
|
|
||||||
<ul className="space-y-4">
|
|
||||||
{countryData.visaProcess.steps.map((process: any) => (
|
|
||||||
<li key={process.number} className="flex gap-4">
|
|
||||||
<span className="font-bold text-blue-600 flex-shrink-0">
|
|
||||||
{process.number}.
|
|
||||||
</span>
|
|
||||||
<span>
|
|
||||||
<strong>{process.title}</strong> – {process.description}
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Sidebar */}
|
|
||||||
<div className="lg:col-span-1">
|
|
||||||
{/* Related Countries */}
|
|
||||||
<div className="bg-white rounded-lg shadow-lg p-6 mb-6">
|
|
||||||
{relatedCountries.map((c: any) => (
|
|
||||||
<div
|
|
||||||
key={c.id}
|
|
||||||
className="flex items-center justify-between py-4 border-b last:border-0 cursor-pointer hover:text-blue-600"
|
|
||||||
>
|
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<img src={c.icon} alt={c.name} className="w-10 h-10" />
|
|
||||||
<h5 className="font-medium">{c.name}</h5>
|
|
||||||
</div>
|
|
||||||
<span className="text-blue-600">›</span>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Contact Box */}
|
|
||||||
<div
|
|
||||||
className="rounded-lg p-6 text-white relative"
|
|
||||||
style={{
|
|
||||||
backgroundImage: `url('${ASSET_URL}/assets/img/inner-page/country-details/bg.jpg')`,
|
|
||||||
backgroundSize: "cover",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="absolute inset-0 bg-black/60 rounded-lg"></div>
|
|
||||||
<div className="relative z-10">
|
|
||||||
<h3 className="text-2xl font-bold mb-2">
|
|
||||||
Visa & Immigration
|
|
||||||
</h3>
|
|
||||||
<p className="mb-6">Need Help? Book Lab Visit</p>
|
|
||||||
|
|
||||||
<div className="space-y-4">
|
|
||||||
<div className="flex gap-3">
|
|
||||||
<div className="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center flex-shrink-0">
|
|
||||||
📞
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span className="text-sm">Call Us:</span>
|
|
||||||
<p className="font-bold">
|
|
||||||
<a href={`tel:${contactInfo.phone}`}>
|
|
||||||
{contactInfo.phone}
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex gap-3">
|
|
||||||
<div className="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center flex-shrink-0">
|
|
||||||
✉️
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span className="text-sm">Mail Us:</span>
|
|
||||||
<p className="font-bold">
|
|
||||||
<a href={`mailto:${contactInfo.email}`}>
|
|
||||||
{contactInfo.email}
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex gap-3">
|
|
||||||
<div className="w-10 h-10 rounded-full bg-blue-600 flex items-center justify-center flex-shrink-0">
|
|
||||||
📍
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span className="text-sm">Location:</span>
|
|
||||||
<p className="font-bold">{contactInfo.location}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
{/* Footer */}
|
|
||||||
<footer
|
|
||||||
className="py-20 px-4 lg:px-8 bg-cover text-white relative"
|
|
||||||
style={{
|
|
||||||
backgroundImage: `url('${ASSET_URL}/assets/img/home-1/footer-bg.jpg')`,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="absolute inset-0 bg-black/60"></div>
|
|
||||||
<div className="max-w-7xl mx-auto relative z-10 text-center">
|
|
||||||
<h2 className="text-3xl font-bold mb-4">
|
|
||||||
<a href="tel:+16336547896">+163 3654 7896</a>
|
|
||||||
</h2>
|
|
||||||
<h2 className="text-xl mb-8">
|
|
||||||
69 Street, 5th Avenue LA, United States
|
|
||||||
</h2>
|
|
||||||
<Link href="/">
|
|
||||||
<img
|
|
||||||
src={`${ASSET_URL}/assets/img/logo/white-logo.svg`}
|
|
||||||
alt="logo"
|
|
||||||
className="h-10 mx-auto mb-8"
|
|
||||||
/>
|
|
||||||
</Link>
|
|
||||||
<ul className="flex flex-wrap justify-center gap-8 mb-8">
|
|
||||||
<li>
|
|
||||||
<a href="/" className="hover:text-blue-300">
|
|
||||||
Home
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="/about" className="hover:text-blue-300">
|
|
||||||
About Us
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="/country-list" className="hover:text-blue-300">
|
|
||||||
Visa
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="/blog" className="hover:text-blue-300">
|
|
||||||
Pages
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="/contact" className="hover:text-blue-300">
|
|
||||||
Contact Us
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<div className="flex justify-center gap-6">
|
|
||||||
<a href="#" className="hover:text-blue-300">
|
|
||||||
𝕏
|
|
||||||
</a>
|
|
||||||
<a href="#" className="hover:text-blue-300">
|
|
||||||
📷
|
|
||||||
</a>
|
|
||||||
<a href="#" className="hover:text-blue-300">
|
|
||||||
in
|
|
||||||
</a>
|
|
||||||
<a href="#" className="hover:text-blue-300">
|
|
||||||
▶
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
233
app/visa/[slug]/VisaDetail.tsx
Normal file
233
app/visa/[slug]/VisaDetail.tsx
Normal file
@@ -0,0 +1,233 @@
|
|||||||
|
import React from "react";
|
||||||
|
import Breadcrumb from "../../components/Breadcrumb";
|
||||||
|
import { type VisaCountry } from "@/api/visa";
|
||||||
|
|
||||||
|
interface VisaDetailProps {
|
||||||
|
country: VisaCountry;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function VisaDetail({ country }: VisaDetailProps) {
|
||||||
|
const { name: rootName, detailedView } = country;
|
||||||
|
const {
|
||||||
|
activeCountry: countryData,
|
||||||
|
relatedCountries,
|
||||||
|
contactInfo,
|
||||||
|
} = country.detailedView;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{/* Breadcrumb-Wrapper Section Start */}
|
||||||
|
<Breadcrumb title={rootName} current={rootName} />
|
||||||
|
|
||||||
|
{/* Country-details Section Start */}
|
||||||
|
<section className="country-details-section section-padding fix">
|
||||||
|
<div className="container">
|
||||||
|
<div className="country-details-wrapper">
|
||||||
|
<div className="row g-4">
|
||||||
|
{/* Main Content */}
|
||||||
|
<div className="col-lg-8">
|
||||||
|
<div className="country-details-post">
|
||||||
|
<div className="details-image">
|
||||||
|
<img src={countryData.mainImage} alt="img" />
|
||||||
|
</div>
|
||||||
|
<div className="country-details-content">
|
||||||
|
<h2>{countryData.name}</h2>
|
||||||
|
<p>{countryData.description}</p>
|
||||||
|
<p className="mt-3">{countryData.additionalInfo}</p>
|
||||||
|
<h5>{countryData.tagline}</h5>
|
||||||
|
|
||||||
|
{/* Visa Types */}
|
||||||
|
<div className="tourist-visa-box">
|
||||||
|
{/* Render mảng đầu tiên (index 0) */}
|
||||||
|
{countryData.visaTypes?.[0] && (
|
||||||
|
<div className="tourist-box style-2">
|
||||||
|
{countryData.visaTypes[0].items.map(
|
||||||
|
(item: any, itemIdx: number) => (
|
||||||
|
<div key={itemIdx} className="tourist-content">
|
||||||
|
<h5>{item.title}</h5>
|
||||||
|
<p>{item.description}</p>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Render mảng thứ hai (index 1) */}
|
||||||
|
{countryData.visaTypes?.[1] && (
|
||||||
|
<div className="tourist-box">
|
||||||
|
{countryData.visaTypes[1].items.map(
|
||||||
|
(item: any, itemIdx: number) => (
|
||||||
|
<div key={itemIdx} className="tourist-content">
|
||||||
|
<h5>{item.title}</h5>
|
||||||
|
<p>{item.description}</p>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Visa Process */}
|
||||||
|
{countryData.visaProcess && (
|
||||||
|
<>
|
||||||
|
<h3 className="text">
|
||||||
|
{countryData.visaProcess.title}
|
||||||
|
</h3>
|
||||||
|
<ul className="list-item">
|
||||||
|
{countryData.visaProcess.steps.map(
|
||||||
|
(process: any, idx: number) => (
|
||||||
|
<li key={idx}>
|
||||||
|
<strong>
|
||||||
|
{process.number}. {process.title}
|
||||||
|
</strong>
|
||||||
|
<span>{process.description}</span>
|
||||||
|
</li>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Gallery */}
|
||||||
|
{countryData.gallery && countryData.gallery.length > 0 && (
|
||||||
|
<div className="row g-4 mb-4">
|
||||||
|
{countryData.gallery.map(
|
||||||
|
(image: string, idx: number) => (
|
||||||
|
<div key={idx} className="col-lg-6">
|
||||||
|
<div className="thumb">
|
||||||
|
<img src={image} alt="gallery-img" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Visa Categories */}
|
||||||
|
{countryData.visaCategories && (
|
||||||
|
<>
|
||||||
|
<h3 className="text mb-3">
|
||||||
|
{countryData.visaCategories.title}
|
||||||
|
</h3>
|
||||||
|
|
||||||
|
{countryData.visaCategories.steps.map(
|
||||||
|
(subGroup: string[], groupIdx: number) => (
|
||||||
|
<ul className="visa-list-2" key={groupIdx}>
|
||||||
|
{subGroup.map((category: string, idx: number) => (
|
||||||
|
<li key={idx}>
|
||||||
|
<i className="fa-solid fa-chevrons-right"></i>
|
||||||
|
{category}
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Service Options */}
|
||||||
|
{countryData.visaService && (
|
||||||
|
<>
|
||||||
|
<h3 className="text">
|
||||||
|
{countryData.visaService.title}
|
||||||
|
</h3>
|
||||||
|
<ul className="list-item">
|
||||||
|
{countryData.visaService.steps.map(
|
||||||
|
(process: any, idx: number) => (
|
||||||
|
<li key={idx}>
|
||||||
|
<strong>
|
||||||
|
{process.number}. {process.title} -
|
||||||
|
</strong>
|
||||||
|
<span> {process.description}</span>
|
||||||
|
</li>
|
||||||
|
),
|
||||||
|
)}
|
||||||
|
</ul>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Sidebar */}
|
||||||
|
<div className="col-lg-4">
|
||||||
|
<div className="country-details-sideber">
|
||||||
|
{relatedCountries.map((relCountry: any, idx: number) => (
|
||||||
|
<div key={idx} className="icon-box-item">
|
||||||
|
<div className="left-item">
|
||||||
|
<div className="icon">
|
||||||
|
<img src={relCountry.icon} alt="img" />
|
||||||
|
</div>
|
||||||
|
<h5>{relCountry.name}</h5>
|
||||||
|
</div>
|
||||||
|
<i className="fa-solid fa-chevrons-right"></i>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{/* Contact Box */}
|
||||||
|
{contactInfo && (
|
||||||
|
<div
|
||||||
|
className="visa-contact-box bg-cover"
|
||||||
|
style={{
|
||||||
|
backgroundImage: `url(${contactInfo.img})`,
|
||||||
|
padding: "30px",
|
||||||
|
borderRadius: "8px",
|
||||||
|
color: "white",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div className="content">
|
||||||
|
<h3>{contactInfo.sectionTitle}</h3>
|
||||||
|
<p>{contactInfo.helpText}</p>
|
||||||
|
|
||||||
|
{/* Phone */}
|
||||||
|
<div className="icon-item">
|
||||||
|
<div className="icon">
|
||||||
|
<i className="fa-solid fa-phone"></i>
|
||||||
|
</div>
|
||||||
|
<div className="cont">
|
||||||
|
<span>{contactInfo.phone.label}: </span>
|
||||||
|
<h6>
|
||||||
|
<a href={contactInfo.phone.link}>
|
||||||
|
{contactInfo.phone.value}
|
||||||
|
</a>
|
||||||
|
</h6>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Email */}
|
||||||
|
<div className="icon-item">
|
||||||
|
<div className="icon">
|
||||||
|
<i className="fa-regular fa-envelope"></i>
|
||||||
|
</div>
|
||||||
|
<div className="cont">
|
||||||
|
<span>{contactInfo.email.label}: </span>
|
||||||
|
<h6>
|
||||||
|
<a href={contactInfo.email.link}>
|
||||||
|
{contactInfo.email.value}
|
||||||
|
</a>
|
||||||
|
</h6>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Location */}
|
||||||
|
<div className="icon-item">
|
||||||
|
<div className="icon">
|
||||||
|
<i className="fa-regular fa-location-dot"></i>
|
||||||
|
</div>
|
||||||
|
<div className="cont">
|
||||||
|
<span>{contactInfo.location.label}: </span>
|
||||||
|
<h6>{contactInfo.location.address}</h6>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -2,17 +2,8 @@
|
|||||||
|
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import visaData from "../visa.json";
|
import VisaDetail from "./VisaDetail";
|
||||||
import Breadcrumb from "../components/Breadcrumb";
|
import { fetchVisaData, type VisaCountry } from "@/api/visa";
|
||||||
|
|
||||||
const ASSET_URL = process.env.NEXT_PUBLIC_API_URL || "";
|
|
||||||
|
|
||||||
interface VisaCountryData {
|
|
||||||
id: number;
|
|
||||||
name: string;
|
|
||||||
icon: string;
|
|
||||||
services: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
interface CountryDetailsProps {
|
interface CountryDetailsProps {
|
||||||
params: Promise<{
|
params: Promise<{
|
||||||
@@ -20,48 +11,39 @@ interface CountryDetailsProps {
|
|||||||
}>;
|
}>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper function to map slugs to country names
|
|
||||||
const getCountryFromSlug = (slug: string): string => {
|
|
||||||
const slugToCountry: { [key: string]: string } = {
|
|
||||||
france: "France",
|
|
||||||
uk: "UK",
|
|
||||||
canada: "Canada",
|
|
||||||
germany: "Germany",
|
|
||||||
spain: "Spain",
|
|
||||||
"south-korea": "South Korea",
|
|
||||||
japan: "Japan",
|
|
||||||
croatia: "Croatia",
|
|
||||||
england: "England",
|
|
||||||
indonesia: "Indonesia",
|
|
||||||
"united-states-of-america": "United States of America",
|
|
||||||
};
|
|
||||||
|
|
||||||
return slugToCountry[slug] || slug;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function CountryDetailsPage({ params }: CountryDetailsProps) {
|
export default function CountryDetailsPage({ params }: CountryDetailsProps) {
|
||||||
const [country, setCountry] = useState<VisaCountryData | null>(null);
|
// 1. Quản lý trạng thái dữ liệu
|
||||||
|
const [country, setCountry] = useState<VisaCountry | null>(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [slug, setSlug] = useState<string>("");
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Unwrap the params Promise
|
const initPage = async () => {
|
||||||
Promise.resolve(params).then((resolvedParams) => {
|
try {
|
||||||
const currentSlug = resolvedParams.slug;
|
setLoading(true);
|
||||||
setSlug(currentSlug);
|
|
||||||
|
|
||||||
const countryName = getCountryFromSlug(currentSlug);
|
// 2. Giải nén params (Vì params là Promise trong Next.js mới)
|
||||||
const foundCountry = visaData.visaSystem.summaryList.find(
|
const resolvedParams = await params;
|
||||||
(c) => c.name === countryName,
|
const currentSlug = resolvedParams.slug;
|
||||||
);
|
|
||||||
|
|
||||||
if (foundCountry) {
|
// 3. Lấy dữ liệu từ API bên trong useEffect
|
||||||
setCountry(foundCountry);
|
const visaData = await fetchVisaData();
|
||||||
|
|
||||||
|
// 4. Tìm nước trong danh sách summaryList dựa trên slug từ URL
|
||||||
|
const found = visaData.hero.summaryList.find(
|
||||||
|
(item: VisaCountry) => item.slug === currentSlug,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (found) {
|
||||||
|
setCountry(found);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Lỗi khi tải dữ liệu:", error);
|
||||||
|
} finally {
|
||||||
|
setLoading(false);
|
||||||
}
|
}
|
||||||
setLoading(false);
|
};
|
||||||
});
|
|
||||||
}, [params]);
|
|
||||||
|
|
||||||
|
initPage();
|
||||||
|
}, [params]);
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center min-h-screen">
|
<div className="flex items-center justify-center min-h-screen">
|
||||||
@@ -70,215 +52,14 @@ export default function CountryDetailsPage({ params }: CountryDetailsProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!country) {
|
// Xử lý khi không tìm thấy dữ liệu
|
||||||
|
if (!country || !country.detailedView?.activeCountry) {
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center justify-center min-h-screen">
|
<div className="flex items-center justify-center min-h-screen">
|
||||||
<h1>Country not found</h1>
|
<h1>Country details not found</h1>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const breadcrumbData = visaData.visaSystem.breadcrumb;
|
return <VisaDetail country={country} />;
|
||||||
const countryData = visaData.visaSystem.detailedView.activeCountry;
|
|
||||||
const relatedCountries = visaData.visaSystem.detailedView.relatedCountries;
|
|
||||||
const contactInfo = visaData.visaSystem.contactInfo;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
{/* Breadcrumb-Wrapper Section Start */}
|
|
||||||
<Breadcrumb
|
|
||||||
title={breadcrumbData.list.title}
|
|
||||||
breadcrumbItems={[
|
|
||||||
{ label: "Home", href: "/" },
|
|
||||||
{ label: countryData.name },
|
|
||||||
]}
|
|
||||||
backgroundImage={`${ASSET_URL}/${breadcrumbData.list.image}`}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Country-details Section Start */}
|
|
||||||
<section className="country-details-section section-padding fix">
|
|
||||||
<div className="container">
|
|
||||||
<div className="country-details-wrapper">
|
|
||||||
<div className="row g-4">
|
|
||||||
{/* Main Content */}
|
|
||||||
<div className="col-lg-8">
|
|
||||||
<div className="country-details-post">
|
|
||||||
<div className="details-image">
|
|
||||||
<img
|
|
||||||
src={`${ASSET_URL}/${countryData.mainImage}`}
|
|
||||||
alt="img"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="country-details-content">
|
|
||||||
<h2>{countryData.name}</h2>
|
|
||||||
<p>{countryData.description}</p>
|
|
||||||
<p className="mt-3">{countryData.additionalInfo}</p>
|
|
||||||
<h5>{countryData.tagline}</h5>
|
|
||||||
|
|
||||||
{/* Visa Types */}
|
|
||||||
<div className="tourist-visa-box">
|
|
||||||
{/* Render mảng đầu tiên (index 0) */}
|
|
||||||
{countryData.visaTypes[0] && (
|
|
||||||
<div className="tourist-box style-2">
|
|
||||||
{countryData.visaTypes[0].items.map(
|
|
||||||
(item: any, itemIdx: number) => (
|
|
||||||
<div key={itemIdx} className="tourist-content">
|
|
||||||
<h5>{item.title}</h5>
|
|
||||||
<p>{item.description}</p>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Render mảng thứ hai (index 1) */}
|
|
||||||
{countryData.visaTypes[1] && (
|
|
||||||
<div className="tourist-box">
|
|
||||||
{countryData.visaTypes[1].items.map(
|
|
||||||
(item: any, itemIdx: number) => (
|
|
||||||
<div key={itemIdx} className="tourist-content">
|
|
||||||
<h5>{item.title}</h5>
|
|
||||||
<p>{item.description}</p>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Visa Process */}
|
|
||||||
<h3 className="text">{countryData.visaProcess.title}</h3>
|
|
||||||
<ul className="list-item">
|
|
||||||
{countryData.visaProcess.steps.map(
|
|
||||||
(process: any, idx: number) => (
|
|
||||||
<li key={idx}>
|
|
||||||
{process.number}. {process.title} –
|
|
||||||
<span>{process.description}</span>
|
|
||||||
</li>
|
|
||||||
),
|
|
||||||
)}
|
|
||||||
</ul>
|
|
||||||
|
|
||||||
{/* Gallery */}
|
|
||||||
<div className="row g-4 mb-4">
|
|
||||||
{countryData.gallery.map((image: string, idx: number) => (
|
|
||||||
<div key={idx} className="col-lg-6">
|
|
||||||
<div className="thumb">
|
|
||||||
<img src={`${ASSET_URL}/${image}`} alt="img" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Visa Categories */}
|
|
||||||
<h3 className="text mb-3">
|
|
||||||
{countryData.visaCategories.title}
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
{countryData.visaCategories.steps.map(
|
|
||||||
(subGroup: string[], groupIdx: number) => (
|
|
||||||
<ul className="visa-list-2" key={groupIdx}>
|
|
||||||
{/* Map lần 2 để render từng chuỗi trong mảng con */}
|
|
||||||
{subGroup.map((category: string, idx: number) => (
|
|
||||||
<li key={idx}>
|
|
||||||
<i className="fa-solid fa-chevrons-right"></i>
|
|
||||||
{category}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ul>
|
|
||||||
),
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Service Options */}
|
|
||||||
<h3 className="text">{countryData.visaService.title}</h3>
|
|
||||||
<ul className="list-item">
|
|
||||||
{countryData.visaService.steps.map(
|
|
||||||
(process: any, idx: number) => (
|
|
||||||
<li key={idx}>
|
|
||||||
{process.number}. {process.title} –
|
|
||||||
<span>{process.description}</span>
|
|
||||||
</li>
|
|
||||||
),
|
|
||||||
)}
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Sidebar */}
|
|
||||||
<div className="col-lg-4">
|
|
||||||
<div className="country-details-sideber">
|
|
||||||
{relatedCountries.map((relCountry: any, idx: number) => (
|
|
||||||
<div key={idx} className="icon-box-item">
|
|
||||||
<div className="left-item">
|
|
||||||
<div className="icon">
|
|
||||||
<img
|
|
||||||
src={`${ASSET_URL}/${relCountry.icon}`}
|
|
||||||
alt="img"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<h5>{relCountry.name}</h5>
|
|
||||||
</div>
|
|
||||||
<i className="fa-solid fa-chevrons-right"></i>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
|
|
||||||
{/* Contact Box */}
|
|
||||||
<div
|
|
||||||
className="visa-contact-box bg-cover"
|
|
||||||
style={{
|
|
||||||
backgroundImage: `url(${ASSET_URL}/assets/img/inner-page/country-details/bg.jpg)`,
|
|
||||||
padding: "30px",
|
|
||||||
borderRadius: "8px",
|
|
||||||
color: "white",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="content">
|
|
||||||
<h3>{contactInfo.sectionTitle}</h3>
|
|
||||||
<p>{contactInfo.helpText}</p>
|
|
||||||
<div className="icon-item">
|
|
||||||
<div className="icon">
|
|
||||||
<i className="fa-solid fa-phone"></i>
|
|
||||||
</div>
|
|
||||||
<div className="cont">
|
|
||||||
<span>{contactInfo.phone.label}: </span>
|
|
||||||
<h6>
|
|
||||||
<a href={`tel:${contactInfo.phone.link}`}>
|
|
||||||
{contactInfo.phone.value}
|
|
||||||
</a>
|
|
||||||
</h6>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="icon-item">
|
|
||||||
<div className="icon">
|
|
||||||
<i className="fa-regular fa-envelope"></i>
|
|
||||||
</div>
|
|
||||||
<div className="cont">
|
|
||||||
<span>{contactInfo.email.label}: </span>
|
|
||||||
<h6>
|
|
||||||
<a href={`mailto:${contactInfo.email.link}`}>
|
|
||||||
{contactInfo.email.value}
|
|
||||||
</a>
|
|
||||||
</h6>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="icon-item">
|
|
||||||
<div className="icon">
|
|
||||||
<i className="fa-regular fa-location-dot"></i>
|
|
||||||
</div>
|
|
||||||
<div className="cont">
|
|
||||||
<span>{contactInfo.location.label}: </span>
|
|
||||||
<h6>{contactInfo.location.address}</h6>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ interface BreadcrumbProps {
|
|||||||
export default function Breadcrumb({
|
export default function Breadcrumb({
|
||||||
title,
|
title,
|
||||||
breadcrumbItems,
|
breadcrumbItems,
|
||||||
backgroundImage = `${ASSET_URL}/assets/img/inner-page/breadcrumb.jpg`,
|
backgroundImage = `${ASSET_URL}/img/inner-page/breadcrumb.jpg`,
|
||||||
showShape = true,
|
showShape = true,
|
||||||
}: BreadcrumbProps) {
|
}: BreadcrumbProps) {
|
||||||
return (
|
return (
|
||||||
@@ -25,7 +25,7 @@ export default function Breadcrumb({
|
|||||||
>
|
>
|
||||||
{showShape && (
|
{showShape && (
|
||||||
<div className="shape">
|
<div className="shape">
|
||||||
<img src={`${ASSET_URL}/assets/img/inner-page/shape.png`} alt="img" />
|
<img src={`${ASSET_URL}/img/inner-page/shape.png`} alt="img" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="container">
|
<div className="container">
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
|
|
||||||
const ASSET_URL = process.env.NEXT_PUBLIC_API_URL || "";
|
|
||||||
|
|
||||||
export const metadata: Metadata = {
|
export const metadata: Metadata = {
|
||||||
title: "Visaway – Immigration & Visa Consulting HTML Template",
|
title: "Visaway – Immigration & Visa Consulting HTML Template",
|
||||||
description: "Visaway – Immigration & Visa Consulting HTML Template",
|
description: "Visaway – Immigration & Visa Consulting HTML Template",
|
||||||
@@ -20,392 +17,8 @@ export default function VisaLayout({
|
|||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* Preloader Start */}
|
|
||||||
<div id="preloader" className="preloader" style={{ display: "none" }}>
|
|
||||||
<div className="animation-preloader">
|
|
||||||
<div className="spinner"></div>
|
|
||||||
<div className="txt-loading">
|
|
||||||
<span data-text-preloader="V" className="letters-loading">
|
|
||||||
{" "}
|
|
||||||
V{" "}
|
|
||||||
</span>
|
|
||||||
<span data-text-preloader="I" className="letters-loading">
|
|
||||||
{" "}
|
|
||||||
I{" "}
|
|
||||||
</span>
|
|
||||||
<span data-text-preloader="S" className="letters-loading">
|
|
||||||
{" "}
|
|
||||||
S{" "}
|
|
||||||
</span>
|
|
||||||
<span data-text-preloader="A" className="letters-loading">
|
|
||||||
{" "}
|
|
||||||
A{" "}
|
|
||||||
</span>
|
|
||||||
<span data-text-preloader="W" className="letters-loading">
|
|
||||||
{" "}
|
|
||||||
W{" "}
|
|
||||||
</span>
|
|
||||||
<span data-text-preloader="A" className="letters-loading">
|
|
||||||
{" "}
|
|
||||||
A{" "}
|
|
||||||
</span>
|
|
||||||
<span data-text-preloader="Y" className="letters-loading">
|
|
||||||
{" "}
|
|
||||||
Y{" "}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<p className="text-center">Loading</p>
|
|
||||||
</div>
|
|
||||||
<div className="loader">
|
|
||||||
<div className="row">
|
|
||||||
<div className="col-3 loader-section section-left">
|
|
||||||
<div className="bg"></div>
|
|
||||||
</div>
|
|
||||||
<div className="col-3 loader-section section-left">
|
|
||||||
<div className="bg"></div>
|
|
||||||
</div>
|
|
||||||
<div className="col-3 loader-section section-right">
|
|
||||||
<div className="bg"></div>
|
|
||||||
</div>
|
|
||||||
<div className="col-3 loader-section section-right">
|
|
||||||
<div className="bg"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* GT Back To Top Start */}
|
|
||||||
<button id="back-top" className="back-to-top show">
|
|
||||||
<i className="fa-regular fa-arrow-up"></i>
|
|
||||||
</button>
|
|
||||||
|
|
||||||
{/* GT MouseCursor Start */}
|
|
||||||
<div className="mouseCursor cursor-outer"></div>
|
|
||||||
<div className="mouseCursor cursor-inner"></div>
|
|
||||||
|
|
||||||
{/* Header-Top-Section Start */}
|
|
||||||
<div className="header-top-section">
|
|
||||||
<div className="container-fluid">
|
|
||||||
<div className="header-top-wrapper">
|
|
||||||
<div className="header-left">
|
|
||||||
<ul className="list">
|
|
||||||
<li className="style-2">
|
|
||||||
<span>Help Line</span>
|
|
||||||
<i className="fa-solid fa-phone"></i>
|
|
||||||
<a href="tel:+093783575222">+09 378 357 5222</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<i className="fa-solid fa-location-dot"></i>
|
|
||||||
69 Street, 5th AvenueLA, United States
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<i className="fa-solid fa-envelope"></i>
|
|
||||||
<a href="mailto:info@example.com">info@example.com</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div className="header-right">
|
|
||||||
<div className="flag-wrap">
|
|
||||||
<div className="flag">
|
|
||||||
<i className="fa-solid fa-globe"></i>
|
|
||||||
</div>
|
|
||||||
<div className="nice-select" tabIndex={0}>
|
|
||||||
<span className="current"> English </span>
|
|
||||||
<ul className="list">
|
|
||||||
<li data-value="1" className="option selected focus">
|
|
||||||
English
|
|
||||||
</li>
|
|
||||||
<li data-value="1" className="option">
|
|
||||||
Bangla
|
|
||||||
</li>
|
|
||||||
<li data-value="1" className="option">
|
|
||||||
Hindi
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="social-item">
|
|
||||||
<a href="#">
|
|
||||||
<i className="fa-brands fa-linkedin"></i>
|
|
||||||
</a>
|
|
||||||
<a href="#">
|
|
||||||
<i className="fa-brands fa-twitter"></i>
|
|
||||||
</a>
|
|
||||||
<a href="#">
|
|
||||||
<i className="fa-brands fa-instagram"></i>
|
|
||||||
</a>
|
|
||||||
<a href="#">
|
|
||||||
<i className="fa-brands fa-youtube"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Offcanvas Area Start */}
|
|
||||||
<div className="fix-area">
|
|
||||||
<div className="offcanvas__info">
|
|
||||||
<div className="offcanvas__wrapper">
|
|
||||||
<div className="offcanvas__content">
|
|
||||||
<div className="offcanvas__top mb-5 d-flex justify-content-between align-items-center">
|
|
||||||
<div className="offcanvas__logo">
|
|
||||||
<a href="/">
|
|
||||||
<img
|
|
||||||
src={`${ASSET_URL}/assets/img/logo/black-logo.svg`}
|
|
||||||
alt="logo-img"
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className="offcanvas__close">
|
|
||||||
<button>
|
|
||||||
<i className="fas fa-times"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<p className="text d-none d-xl-block">
|
|
||||||
Nullam dignissim, ante scelerisque the is euismod fermentum odio
|
|
||||||
sem semper the is erat, a feugiat leo urna eget eros. Duis
|
|
||||||
Aenean a imperdiet risus.
|
|
||||||
</p>
|
|
||||||
<div className="mobile-menu fix mb-3"></div>
|
|
||||||
<div className="offcanvas__contact d-xl-block">
|
|
||||||
<h4 className="d-xl-block">Contact Info</h4>
|
|
||||||
<ul className="d-xl-block">
|
|
||||||
<li className="d-flex align-items-center">
|
|
||||||
<div className="offcanvas__contact-icon">
|
|
||||||
<i className="fal fa-map-marker-alt"></i>
|
|
||||||
</div>
|
|
||||||
<div className="offcanvas__contact-text">
|
|
||||||
<a target="_blank" href="#">
|
|
||||||
Main Street, Melbourne, Australia
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li className="d-flex align-items-center">
|
|
||||||
<div className="offcanvas__contact-icon mr-15">
|
|
||||||
<i className="fal fa-envelope"></i>
|
|
||||||
</div>
|
|
||||||
<div className="offcanvas__contact-text">
|
|
||||||
<a href="mailto:info@example.com">
|
|
||||||
<span>info@example.com</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li className="d-flex align-items-center">
|
|
||||||
<div className="offcanvas__contact-icon mr-15">
|
|
||||||
<i className="fal fa-clock"></i>
|
|
||||||
</div>
|
|
||||||
<div className="offcanvas__contact-text">
|
|
||||||
<a target="_blank" href="#">
|
|
||||||
Mod-friday, 09am -05pm
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
<li className="d-flex align-items-center">
|
|
||||||
<div className="offcanvas__contact-icon mr-15">
|
|
||||||
<i className="far fa-phone"></i>
|
|
||||||
</div>
|
|
||||||
<div className="offcanvas__contact-text">
|
|
||||||
<a href="tel:+11002345909">+11002345909</a>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<div className="social-icon d-flex align-items-center">
|
|
||||||
<a href="#">
|
|
||||||
<i className="fab fa-facebook-f"></i>
|
|
||||||
</a>
|
|
||||||
<a href="#">
|
|
||||||
<i className="fab fa-twitter"></i>
|
|
||||||
</a>
|
|
||||||
<a href="#">
|
|
||||||
<i className="fab fa-youtube"></i>
|
|
||||||
</a>
|
|
||||||
<a href="#">
|
|
||||||
<i className="fab fa-linkedin-in"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="offcanvas__overlay"></div>
|
|
||||||
|
|
||||||
{/* Header Section Start */}
|
|
||||||
{/* <header id="header-sticky" className="header-1">
|
|
||||||
<div className="container-fluid">
|
|
||||||
<div className="mega-menu-wrapper">
|
|
||||||
<div className="header-main">
|
|
||||||
<div className="header-left">
|
|
||||||
<div className="logo">
|
|
||||||
<a href="/" className="header-logo-2">
|
|
||||||
<img
|
|
||||||
src={`${ASSET_URL}/assets/img/logo/black-logo.svg`}
|
|
||||||
alt="logo-img"
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div className="mean__menu-wrapper">
|
|
||||||
<div className="main-menu">
|
|
||||||
<nav id="mobile-menu">
|
|
||||||
<ul>
|
|
||||||
<li className="has-dropdown active menu-thumb">
|
|
||||||
<a href="/"> Home </a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="/about">About Us</a>
|
|
||||||
</li>
|
|
||||||
<li className="has-dropdown">
|
|
||||||
<a href="#"> Pages </a>
|
|
||||||
<ul className="submenu">
|
|
||||||
<li>
|
|
||||||
<a href="/services">Services</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="/visa">Country List</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="/pricing">Our Pricing</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="/appointment">Appointment</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="/visa"> VISA </a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="/blog"> Blog </a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="/contact">Contact Us</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="header-right d-flex align-items-center mt-0">
|
|
||||||
<div className="header-call-item">
|
|
||||||
<a href="#" className="main-header__search search-toggler">
|
|
||||||
<i className="fa-regular fa-magnifying-glass"></i>
|
|
||||||
</a>
|
|
||||||
<a href="/contact" className="theme-btn">
|
|
||||||
Apply now
|
|
||||||
<i className="fa-solid fa-arrow-right"></i>
|
|
||||||
</a>
|
|
||||||
<div className="header__hamburger my-auto">
|
|
||||||
<div className="sidebar__toggle">
|
|
||||||
<i className="fa-solid fa-bars-staggered"></i>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</header> */}
|
|
||||||
|
|
||||||
{/* Search Area Start */}
|
|
||||||
<div className="search-popup">
|
|
||||||
<div className="search-popup__overlay search-toggler"></div>
|
|
||||||
<div className="search-popup__content">
|
|
||||||
<form
|
|
||||||
role="search"
|
|
||||||
method="get"
|
|
||||||
className="search-popup__form"
|
|
||||||
action="#"
|
|
||||||
>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
id="search"
|
|
||||||
name="search"
|
|
||||||
placeholder="Search Here..."
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
aria-label="search submit"
|
|
||||||
className="search-btn"
|
|
||||||
>
|
|
||||||
<span>
|
|
||||||
<i className="fa-regular fa-magnifying-glass"></i>
|
|
||||||
</span>
|
|
||||||
</button>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Main Content */}
|
{/* Main Content */}
|
||||||
{children}
|
{children}
|
||||||
|
|
||||||
{/* Footer Section Start */}
|
|
||||||
{/* <footer
|
|
||||||
className="footer-section fix bg-cover"
|
|
||||||
style={{
|
|
||||||
backgroundImage: `url(${ASSET_URL}/assets/img/home-1/footer-bg.jpg)`,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<div className="container">
|
|
||||||
<div className="footer-wrapper">
|
|
||||||
<div className="row">
|
|
||||||
<div className="col-xl-12">
|
|
||||||
<div className="footer-item">
|
|
||||||
<h2>
|
|
||||||
<a href="tel:+16336547896">+163 3654 7896</a>
|
|
||||||
</h2>
|
|
||||||
<h2 className="text">
|
|
||||||
69 Street, 5th AvenueLA, United States
|
|
||||||
</h2>
|
|
||||||
<div className="footer-list-item">
|
|
||||||
<a href="/">
|
|
||||||
<img
|
|
||||||
src={`${ASSET_URL}/assets/img/logo/white-logo.svg`}
|
|
||||||
alt="img"
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
<ul className="footer-list">
|
|
||||||
<li>
|
|
||||||
<a href="/">Home</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="/about">About Us</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="/visa">Visa</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="/blog">Pages</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="/blog">Article</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a href="/contact">Contact Us</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<div className="social-icon">
|
|
||||||
<a href="#">
|
|
||||||
<i className="fa-brands fa-twitter"></i>
|
|
||||||
</a>
|
|
||||||
<a href="#">
|
|
||||||
<i className="fa-brands fa-instagram"></i>
|
|
||||||
</a>
|
|
||||||
<a href="#">
|
|
||||||
<i className="fa-brands fa-linkedin"></i>
|
|
||||||
</a>
|
|
||||||
<a href="#">
|
|
||||||
<i className="fa-brands fa-youtube"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</footer> */}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,40 +1,52 @@
|
|||||||
"use client";
|
// app/visa/page.tsx
|
||||||
|
|
||||||
import visaData from "./visa.json";
|
import Breadcrumb from "../components/Breadcrumb";
|
||||||
import Breadcrumb from "./components/Breadcrumb";
|
import { fetchVisaData, type VisaCountry } from "@/api/visa";
|
||||||
|
|
||||||
const ASSET_URL = process.env.NEXT_PUBLIC_API_URL || "";
|
export default async function VisaListPage() {
|
||||||
|
// Fetch all visa countries từ API
|
||||||
|
let visaCountries: any[] = [];
|
||||||
|
let visaHero: any = {};
|
||||||
|
const visaTitle = "Visa Services";
|
||||||
|
const breadcrumbCurrent = "Visa Services";
|
||||||
|
let error: string | null = null;
|
||||||
|
try {
|
||||||
|
const visaData = await fetchVisaData();
|
||||||
|
visaCountries = visaData.hero.summaryList.map((country: VisaCountry) => ({
|
||||||
|
...country,
|
||||||
|
icon: country.icon,
|
||||||
|
}));
|
||||||
|
visaHero = visaData.hero;
|
||||||
|
} catch (err) {
|
||||||
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
||||||
|
console.error("Error fetching visa countries:", errorMessage);
|
||||||
|
error = errorMessage;
|
||||||
|
}
|
||||||
|
|
||||||
interface VisaCountry {
|
// Fallback message nếu có error
|
||||||
id: number;
|
if (error && visaCountries.length === 0) {
|
||||||
name: string;
|
return (
|
||||||
icon: string;
|
<>
|
||||||
services: string[];
|
<Breadcrumb title={visaTitle} current={breadcrumbCurrent} />
|
||||||
}
|
<section className="visa-provide-section section-padding section-bg-1 fix">
|
||||||
|
<div className="container">
|
||||||
const visaCountries: VisaCountry[] = visaData.visaSystem.summaryList.map(
|
<div className="row">
|
||||||
(country) => ({
|
<div className="col-12 text-center">
|
||||||
...country,
|
<p className="text-danger">
|
||||||
icon: `${ASSET_URL}/${country.icon}`,
|
Error loading visa services: {error}
|
||||||
}),
|
</p>
|
||||||
);
|
</div>
|
||||||
|
</div>
|
||||||
export default function VisaListPage() {
|
</div>
|
||||||
const getSlug = (countryName: string): string => {
|
</section>
|
||||||
return countryName.toLowerCase().replace(/\s+/g, "-");
|
</>
|
||||||
};
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* Breadcrumb-Wrapper Section Start */}
|
{/* Breadcrumb-Wrapper Section Start */}
|
||||||
<Breadcrumb
|
<Breadcrumb title={visaHero.title} current={visaHero.title} />
|
||||||
title={visaData.visaSystem.breadcrumb.list.title}
|
|
||||||
breadcrumbItems={[
|
|
||||||
{ label: "Home", href: "/" },
|
|
||||||
{ label: visaData.visaSystem.breadcrumb.list.title },
|
|
||||||
]}
|
|
||||||
backgroundImage={`${ASSET_URL}/${visaData.visaSystem.breadcrumb.list.image}`}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Service Section Start */}
|
{/* Service Section Start */}
|
||||||
<section className="visa-provide-section section-padding section-bg-1 fix">
|
<section className="visa-provide-section section-padding section-bg-1 fix">
|
||||||
@@ -46,45 +58,58 @@ export default function VisaListPage() {
|
|||||||
<div className="visa-top-item">
|
<div className="visa-top-item">
|
||||||
<div className="visa-left">
|
<div className="visa-left">
|
||||||
<div className="icon">
|
<div className="icon">
|
||||||
<img src={country.icon} alt="img" />
|
<img
|
||||||
|
src={country.icon}
|
||||||
|
alt={country.name}
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="content">
|
<div className="content">
|
||||||
<p>Visa Service</p>
|
<p>Visa Service</p>
|
||||||
<h3>
|
<h3>
|
||||||
<a href={`/visa/${getSlug(country.name)}`}>
|
<a href={`/visa/${country.slug}`}>{country.name}</a>
|
||||||
{country.name}
|
|
||||||
</a>
|
|
||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a
|
|
||||||
href={`/visa/${getSlug(country.name)}`}
|
{/* Read More Button */}
|
||||||
className="theme-btn"
|
<a href={`/visa/${country.slug}`} className="theme-btn">
|
||||||
>
|
|
||||||
Read More
|
Read More
|
||||||
<i className="fa-solid fa-arrow-right"></i>
|
<i className="fa-solid fa-arrow-right"></i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
{/* Services List */}
|
||||||
<div className="visa-list-item">
|
<div className="visa-list-item">
|
||||||
|
{/* First Column */}
|
||||||
<ul className="list">
|
<ul className="list">
|
||||||
<li>
|
{country.services[0] && (
|
||||||
<i className="fa-regular fa-arrow-right"></i>
|
<li>
|
||||||
{country.services[0]}
|
<i className="fa-regular fa-arrow-right"></i>
|
||||||
</li>
|
{country.services[0]}
|
||||||
<li>
|
</li>
|
||||||
<i className="fa-regular fa-arrow-right"></i>
|
)}
|
||||||
{country.services[1]}
|
{country.services[1] && (
|
||||||
</li>
|
<li>
|
||||||
|
<i className="fa-regular fa-arrow-right"></i>
|
||||||
|
{country.services[1]}
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
{/* Second Column */}
|
||||||
<ul className="list">
|
<ul className="list">
|
||||||
<li>
|
{country.services[2] && (
|
||||||
<i className="fa-regular fa-arrow-right"></i>
|
<li>
|
||||||
{country.services[2]}
|
<i className="fa-regular fa-arrow-right"></i>
|
||||||
</li>
|
{country.services[2]}
|
||||||
<li>
|
</li>
|
||||||
<i className="fa-regular fa-arrow-right"></i>
|
)}
|
||||||
{country.services[3]}
|
{country.services[3] && (
|
||||||
</li>
|
<li>
|
||||||
|
<i className="fa-regular fa-arrow-right"></i>
|
||||||
|
{country.services[3]}
|
||||||
|
</li>
|
||||||
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,291 +1,300 @@
|
|||||||
{
|
{
|
||||||
"visaSystem": {
|
"hero": {
|
||||||
"breadcrumb": {
|
"title": "Visa",
|
||||||
"list": {
|
"summaryList": [
|
||||||
"title": "Country List",
|
|
||||||
"image": "assets/img/inner-page/breadcrumb.jpg"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"summaryList": [
|
|
||||||
{
|
|
||||||
"id": 1,
|
|
||||||
"name": "France",
|
|
||||||
"icon": "assets/img/home-2/visa/03.png",
|
|
||||||
"services": [
|
|
||||||
"Student Visa & Admission",
|
|
||||||
"Work Visa – H1B",
|
|
||||||
"Work permit for Canada",
|
|
||||||
"Student Visa for Canada"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 2,
|
|
||||||
"name": "UK",
|
|
||||||
"icon": "assets/img/home-2/visa/11.png",
|
|
||||||
"services": [
|
|
||||||
"Student Visa & Admission",
|
|
||||||
"Work Visa – H1B",
|
|
||||||
"Work permit for Canada",
|
|
||||||
"Student Visa for Canada"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 3,
|
|
||||||
"name": "Canada",
|
|
||||||
"icon": "assets/img/home-2/visa/02.png",
|
|
||||||
"services": [
|
|
||||||
"Student Visa & Admission",
|
|
||||||
"Work Visa – H1B",
|
|
||||||
"Work permit for Canada",
|
|
||||||
"Student Visa for Canada"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"id": 4,
|
|
||||||
"name": "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",
|
|
||||||
"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",
|
|
||||||
"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",
|
|
||||||
"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",
|
|
||||||
"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",
|
|
||||||
"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",
|
|
||||||
"icon": "assets/img/home-2/visa/18.png",
|
|
||||||
"services": [
|
|
||||||
"Student Visa & Admission",
|
|
||||||
"Work Visa – H1B",
|
|
||||||
"Work permit for Canada",
|
|
||||||
"Student Visa for Canada"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"detailedView": {
|
|
||||||
"activeCountry": {
|
|
||||||
"id": 1,
|
|
||||||
"name": "United States of America ",
|
|
||||||
"title": "COUNTRY USA",
|
|
||||||
"mainImage": "assets/img/inner-page/country-details/details-1.jpg",
|
|
||||||
"description": "The United States is one of the most popular destinations for international students and immigrants, 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": [
|
|
||||||
{
|
|
||||||
"category": "Tourist & Work",
|
|
||||||
"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"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"category": "Student & Family",
|
|
||||||
"items": [
|
|
||||||
{
|
|
||||||
"title": "Student",
|
|
||||||
"description": "Broad term that can refer to various aspects of interconnectedness"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"title": "Tourist Visa",
|
|
||||||
"description": "Broad term that can refer to various aspects of interconnectedness"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"visaProcess": {
|
|
||||||
"title": "USA 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 USA 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 USA 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,
|
"id": 1,
|
||||||
"name": "Canada",
|
"name": "France",
|
||||||
"icon": "assets/img/inner-page/country-details/01.png"
|
"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": "United States of America ",
|
||||||
|
"title": "COUNTRY USA",
|
||||||
|
"mainImage": "assets/img/inner-page/country-details/details-1.jpg",
|
||||||
|
"description": "The United States is one of the most popular destinations for international students and immigrants, 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": [
|
||||||
|
{
|
||||||
|
"category": "Tourist & Work",
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"category": "Student & Family",
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"title": "Student",
|
||||||
|
"description": "Broad term that can refer to various aspects of interconnectedness"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"title": "Tourist Visa",
|
||||||
|
"description": "Broad term that can refer to various aspects of interconnectedness"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"visaProcess": {
|
||||||
|
"title": "USA 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 USA 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 USA 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": "USA",
|
||||||
|
"icon": "assets/img/inner-page/country-details/03.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 4,
|
||||||
|
"name": "Saint Helena",
|
||||||
|
"icon": "assets/img/inner-page/country-details/05.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 5,
|
||||||
|
"name": "Iran",
|
||||||
|
"icon": "assets/img/inner-page/country-details/06.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 6,
|
||||||
|
"name": "Spain",
|
||||||
|
"icon": "assets/img/inner-page/country-details/07.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 7,
|
||||||
|
"name": "Japan",
|
||||||
|
"icon": "assets/img/inner-page/country-details/08.png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"contactInfo": {
|
||||||
|
"sectionTitle": "Visa & Immigration",
|
||||||
|
"helpText": "Need Help? Book Lab Visit",
|
||||||
|
"img": "assets/img/inner-page/country-details/contact-bg.jpg",
|
||||||
|
"phone": {
|
||||||
|
"label": "Call Us",
|
||||||
|
"value": "+009 438 222 9540",
|
||||||
|
"link": "tel:+0094382229540"
|
||||||
|
},
|
||||||
|
"email": {
|
||||||
|
"label": "Mail Us",
|
||||||
|
"value": "infor@xridergamil.com",
|
||||||
|
"link": "mailto:infor@xridergamil.com"
|
||||||
|
},
|
||||||
|
"location": {
|
||||||
|
"label": "Location",
|
||||||
|
"address": "Toronto, Montreal, City 2026"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 2,
|
"id": 2,
|
||||||
"name": "USA",
|
"name": "UK",
|
||||||
"icon": "assets/img/inner-page/country-details/02.png"
|
"slug": "uk",
|
||||||
|
"icon": "assets/img/home-2/visa/11.png",
|
||||||
|
"services": [
|
||||||
|
"Student Visa & Admission",
|
||||||
|
"Work Visa – H1B",
|
||||||
|
"Work permit for Canada",
|
||||||
|
"Student Visa for Canada"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 3,
|
"id": 3,
|
||||||
"name": "USA",
|
"name": "Canada",
|
||||||
"icon": "assets/img/inner-page/country-details/03.png"
|
"slug": "canada",
|
||||||
|
"icon": "assets/img/home-2/visa/02.png",
|
||||||
|
"services": [
|
||||||
|
"Student Visa & Admission",
|
||||||
|
"Work Visa – H1B",
|
||||||
|
"Work permit for Canada",
|
||||||
|
"Student Visa for Canada"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 4,
|
"id": 4,
|
||||||
"name": "Saint Helena",
|
"name": "Germany",
|
||||||
"icon": "assets/img/inner-page/country-details/05.png"
|
"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,
|
"id": 5,
|
||||||
"name": "Iran",
|
"name": "Spain",
|
||||||
"icon": "assets/img/inner-page/country-details/06.png"
|
"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,
|
"id": 6,
|
||||||
"name": "Spain",
|
"name": "South Korea",
|
||||||
"icon": "assets/img/inner-page/country-details/07.png"
|
"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,
|
"id": 7,
|
||||||
"name": "Japan",
|
"name": "Japan",
|
||||||
"icon": "assets/img/inner-page/country-details/08.png"
|
"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"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
|
||||||
"contactInfo": {
|
|
||||||
"sectionTitle": "Visa & Immigration",
|
|
||||||
"helpText": "Need Help? Book Lab Visit",
|
|
||||||
"phone": {
|
|
||||||
"label": "Call Us",
|
|
||||||
"value": "+009 438 222 9540",
|
|
||||||
"link": "tel:+0094382229540"
|
|
||||||
},
|
|
||||||
"email": {
|
|
||||||
"label": "Mail Us",
|
|
||||||
"value": "infor@xridergamil.com",
|
|
||||||
"link": "mailto:infor@xridergamil.com"
|
|
||||||
},
|
|
||||||
"location": {
|
|
||||||
"label": "Location",
|
|
||||||
"address": "Toronto, Montreal, City 2026"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user