feat: support custom domain (#462)

* feat: add custom domain CRUD

* chore: fetch organization in layout in server before render

* debugging

* update log
This commit is contained in:
Rotimi Best
2024-09-04 06:32:54 +01:00
committed by GitHub
parent d1b38ca61e
commit 12d7a1ac3c
25 changed files with 915 additions and 221 deletions
@@ -0,0 +1,133 @@
// Code from https://github.com/vercel/platforms/blob/1ed55b13bcae97b037c69ec40b4c32df21c2412c/lib/domains.ts
import {
DomainResponse,
DomainConfigResponse,
DomainVerificationResponse
} from '$lib/utils/types/org';
import { PROJECT_ID_VERCEL, TEAM_ID_VERCEL, AUTH_BEARER_TOKEN } from '$env/static/private';
export const addDomainToVercel = async (domain: string) => {
return await fetch(
`https://api.vercel.com/v10/projects/${PROJECT_ID_VERCEL}/domains${
TEAM_ID_VERCEL ? `?teamId=${TEAM_ID_VERCEL}` : ''
}`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${AUTH_BEARER_TOKEN}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: domain
// Optional: Redirect www. to root domain
// ...(domain.startsWith("www.") && {
// redirect: domain.replace("www.", ""),
// }),
})
}
).then((res) => res.json());
};
export const removeDomainFromVercelProject = async (domain: string) => {
return await fetch(
`https://api.vercel.com/v9/projects/${PROJECT_ID_VERCEL}/domains/${domain}${
TEAM_ID_VERCEL ? `?teamId=${TEAM_ID_VERCEL}` : ''
}`,
{
headers: {
Authorization: `Bearer ${AUTH_BEARER_TOKEN}`
},
method: 'DELETE'
}
).then((res) => res.json());
};
export const removeDomainFromVercelTeam = async (domain: string) => {
return await fetch(
`https://api.vercel.com/v6/domains/${domain}${
TEAM_ID_VERCEL ? `?teamId=${TEAM_ID_VERCEL}` : ''
}`,
{
headers: {
Authorization: `Bearer ${AUTH_BEARER_TOKEN}`
},
method: 'DELETE'
}
).then((res) => res.json());
};
export const getDomainResponse = async (
domain: string
): Promise<DomainResponse & { error: { code: string; message: string } }> => {
return await fetch(
`https://api.vercel.com/v9/projects/${PROJECT_ID_VERCEL}/domains/${domain}${
TEAM_ID_VERCEL ? `?teamId=${TEAM_ID_VERCEL}` : ''
}`,
{
method: 'GET',
headers: {
Authorization: `Bearer ${AUTH_BEARER_TOKEN}`,
'Content-Type': 'application/json'
}
}
).then((res) => {
return res.json();
});
};
export const getConfigResponse = async (domain: string): Promise<DomainConfigResponse> => {
return await fetch(
`https://api.vercel.com/v6/domains/${domain}/config${
TEAM_ID_VERCEL ? `?teamId=${TEAM_ID_VERCEL}` : ''
}`,
{
method: 'GET',
headers: {
Authorization: `Bearer ${AUTH_BEARER_TOKEN}`,
'Content-Type': 'application/json'
}
}
).then((res) => res.json());
};
export const verifyDomain = async (domain: string): Promise<DomainVerificationResponse> => {
return await fetch(
`https://api.vercel.com/v9/projects/${PROJECT_ID_VERCEL}/domains/${domain}/verify${
TEAM_ID_VERCEL ? `?teamId=${TEAM_ID_VERCEL}` : ''
}`,
{
method: 'POST',
headers: {
Authorization: `Bearer ${AUTH_BEARER_TOKEN}`,
'Content-Type': 'application/json'
}
}
).then((res) => res.json());
};
export const getSubdomain = (name: string, apexName: string) => {
if (name === apexName) return null;
return name.slice(0, name.length - apexName.length - 1);
};
export const getApexDomain = (url: string) => {
let domain;
try {
domain = new URL(url).hostname;
} catch (e) {
return '';
}
const parts = domain.split('.');
if (parts.length > 2) {
// if it's a subdomain (e.g. project.vercel.app), return the last 2 parts
return parts.slice(-2).join('.');
}
// if it's a normal domain (e.g. training.yourdomain.com), we return the domain
return domain;
};
// courtesy of ChatGPT: https://sharegpt.com/c/pUYXtRs
export const validDomainRegex = new RegExp(
/^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$/
);
@@ -0,0 +1,15 @@
import { supabase } from '$lib/utils/functions/supabase';
export async function sendDomainRequest(key: string, domain: string): Promise<Response> {
const { data } = await supabase.auth.getSession();
const accessToken = data.session?.access_token || '';
return fetch('/api/domain', {
method: 'POST',
body: JSON.stringify({ params: { key, domain } }),
headers: {
'Content-Type': 'application/json',
Authorization: `${accessToken}`
}
});
}
@@ -73,15 +73,7 @@ export async function getOrganizations(userId: string, isOrgSite?: boolean, orgS
role_id,
created_at,
organization!organizationmember_organization_id_fkey (
id,
name,
siteName,
avatar_url,
landingpage,
customization,
is_restricted,
theme,
created_at,
*,
organization_plan(
plan_name,
is_active,
@@ -107,18 +99,10 @@ export async function getOrganizations(userId: string, isOrgSite?: boolean, orgS
if (Array.isArray(data) && data.length) {
data.forEach((orgMember) => {
orgsArray.push({
id: orgMember?.organization?.id,
name: orgMember?.organization?.name,
shortName: orgMember?.organization?.name?.substring(0, 2)?.toUpperCase() || '',
siteName: orgMember?.organization?.siteName,
theme: orgMember?.organization?.theme,
avatar_url: orgMember?.organization?.avatar_url,
...(orgMember?.organization || {}),
memberId: orgMember?.id,
role_id: orgMember?.role_id,
landingpage: orgMember?.organization?.landingpage,
is_restricted: orgMember?.organization?.is_restricted,
customization: orgMember?.organization?.customization,
organization_plan: orgMember?.organization?.organization_plan
role_id: parseInt(orgMember?.role_id),
shortName: orgMember?.organization?.name?.substring(0, 2)?.toUpperCase() || ''
});
});
@@ -220,7 +204,7 @@ export async function getCourseBySiteName(siteName: string) {
return data;
}
export async function getCurrentOrg(siteName: string, justGet = false) {
export async function getCurrentOrg(siteName: string, justGet = false, isCustomDomain = false) {
const { data, error } = await supabase
.from('organization')
.select(
@@ -233,13 +217,18 @@ export async function getCurrentOrg(siteName: string, justGet = false) {
is_restricted,
customization,
theme,
favicon,
customDomain,
isCustomDomainVerified,
customCode,
organization_plan(
plan_name,
is_active
)
`
)
.eq('siteName', siteName)
.eq(isCustomDomain ? 'customDomain' : 'siteName', siteName)
.filter('isCustomDomainVerified', 'eq', isCustomDomain ? true : undefined)
.returns<CurrentOrg[]>();
console.log('data =', data);
console.log('error =', error);
@@ -194,7 +194,8 @@
"team_members": "Teammitglieder",
"back": "Zurück zu den Einstellungen",
"download_lessons": "Führen Sie ein Upgrade durch, um Lektionen herunterzuladen",
"download_course": "Upgrade zum Download-Kurs"
"download_course": "Upgrade zum Download-Kurs",
"domain": "Aktualisieren Sie Ihren Plan, um benutzerdefinierte Domänen hinzuzufügen"
},
"audience": {
"title": "Publikum",
@@ -923,12 +924,23 @@
"settings": {
"domains": {
"add": "Hinzufügen",
"work_together": "Fügen Sie Ihre Teamkollegen oder Mitarbeiter zu Ihrer Organisation hinzu. Beginnen Sie mit der Zusammenarbeit",
"url": "URL",
"update": "Domäne aktualisieren",
"custom": "Benutzerdefinierten Domain",
"domain": "Fügen Sie Ihren eigenen Domainnamen hinzu",
"title": "Benutzerdefinierten Domain"
"title": "Benutzerdefinierten Domain",
"save": "Speichern",
"your_domain": "Ihre Domain",
"custom_domain_error": "Sie können eine Top-Level-Domain nicht als benutzerdefinierte Domain hinzufügen. Verwenden Sie stattdessen eine Subdomain wie „Kurse.[IhreWebsite].com“ oder „www.[IhreWebsite].com“.",
"custom_domain_success": "Benutzerdefinierte Domäne erfolgreich hinzugefügt",
"dns_description": "Legen Sie bei Ihrem DNS-Anbieter den folgenden Eintrag fest, um fortzufahren:",
"dns_type": "Typ",
"dns_value": "Wert",
"dns_name": "Name",
"refresh": "Aktualisieren",
"remove": "Entfernen",
"custom_favicon": "Benutzerdefiniertes Favicon",
"custom_code": "Benutzerdefinierter Code"
},
"customize-lms": {
"title": "LMS anpassen",
@@ -1084,7 +1096,8 @@
"learn": "Erfahren Sie mehr",
"month": "Monat",
"monthly": "Monatlich",
"annually": "Jährlich"
"annually": "Jährlich",
"save": "Sparen Sie 2 Monate"
},
"plan_names": {
"free": "Frei",
@@ -1206,9 +1219,9 @@
"update_organization": "Organisation aktualisieren",
"team": {
"heading": "Team",
"sub_heading": "Richten Sie Ihre Website ein",
"body": "Fügen Sie Ihrer Organisation Teamkollegen hinzu, damit Sie beide an Projekten zusammenarbeiten können.",
"button": "Team verwalten"
"button": "Team verwalten",
"sub_heading": "Stellen Sie Ihr Team zusammen"
},
"custom_domain": {
"heading": "Benutzerdefinierten Domain",
@@ -1239,7 +1252,10 @@
},
"profile_picture": {
"heading": "Profilbild",
"upload_image": "Bild hochladen"
"upload_image": "Bild hochladen",
"file_size": "Maximale Dateigröße:",
"accepted": "Akzeptiert:",
"validation_error": "Die Dateigröße überschreitet die maximale Grenze:"
}
},
"tabs": {
@@ -66,7 +66,10 @@
"profile": {
"profile_picture": {
"heading": "Profile Picture",
"upload_image": "Upload Image"
"upload_image": "Upload Image",
"file_size": "Max file size:",
"accepted": "Accepted:",
"validation_error": "File size exceeds the maximum limit:"
},
"personal_information": {
"heading": "Personal Information",
@@ -101,7 +104,7 @@
},
"team": {
"heading": "Team",
"sub_heading": "Set up your website",
"sub_heading": "Set up your team",
"body": "Add team mates to your organization so you can both collaborate on projects.",
"button": "Manage Team"
}
@@ -224,6 +227,7 @@
"heading": "Upgrade Plan",
"thanks": "Thank you for your support",
"plan": "Your plan comes with cool perks and benefits including access to all future features we release.",
"save": "Save 2 months",
"close": "Close",
"learn": "Learn more",
"month": "month",
@@ -332,11 +336,22 @@
"domains": {
"title": "Custom domain",
"add": "Add",
"work_together": "Add your team mates or collaborators to your organization. Start working together",
"url": "URL",
"update": "Update Domain",
"custom": "Custom domain",
"domain": "Add your own domain name"
"domain": "Add your own domain name",
"save": "Save",
"your_domain": "Your Domain",
"custom_domain_error": "You can't add a top level domain as custom domain. Instead, use a subdomain like 'courses.[yourwebsite].com' or 'www.[yourwebsite].com'.",
"custom_domain_success": "Custom domain added successfully",
"dns_description": "Set the following record on your DNS provider to continue:",
"dns_type": "Type",
"dns_value": "Value",
"dns_name": "Name",
"refresh": "Refresh",
"remove": "Remove",
"custom_favicon": "Custom favicon",
"custom_code": "Custom code"
},
"customize_lms": {
"title": "Customize LMS",
@@ -1119,6 +1134,7 @@
"upgrade": {
"certificate": "Upgrade your plan to generate certificates",
"team": "Upgrade your plan to add team members",
"domain": "Upgrade your plan to add custom domains",
"team_members": "Team members",
"back": "Back to Settings",
"download_lessons": "Upgrade to download lessons",
@@ -194,7 +194,8 @@
"team_members": "Miembros del equipo",
"back": "Volver a configuración",
"download_lessons": "Actualice para descargar lecciones",
"download_course": "Actualizar para descargar el curso"
"download_course": "Actualizar para descargar el curso",
"domain": "Actualice su plan para agregar dominios personalizados"
},
"audience": {
"title": "Audiencia",
@@ -923,12 +924,23 @@
"settings": {
"domains": {
"add": "Agregar",
"work_together": "Agregue sus compañeros de equipo o colaboradores a su organización. Empezar a trabajar juntos",
"url": "URL",
"update": "Actualizar dominio",
"custom": "Dominio personalizado",
"domain": "Añade tu propio nombre de dominio",
"title": "Dominio personalizado"
"title": "Dominio personalizado",
"save": "Ahorrar",
"your_domain": "Tu dominio",
"custom_domain_error": "No puede agregar un dominio de nivel superior como dominio personalizado. En su lugar, utilice un subdominio como 'cursos.[susitio web].com' o 'www.[susitio web].com'.",
"custom_domain_success": "Dominio personalizado agregado exitosamente",
"dns_description": "Establezca el siguiente registro en su proveedor de DNS para continuar:",
"dns_type": "Tipo",
"dns_value": "Valor",
"dns_name": "Nombre",
"refresh": "Refrescar",
"remove": "Eliminar",
"custom_favicon": "favicon personalizado",
"custom_code": "código personalizado"
},
"customize-lms": {
"title": "Personalizar LMS",
@@ -1084,7 +1096,8 @@
"learn": "Aprende más",
"month": "mes",
"monthly": "Mensual",
"annually": "Anualmente"
"annually": "Anualmente",
"save": "Ahorra 2 meses"
},
"plan_names": {
"free": "Gratis",
@@ -1206,9 +1219,9 @@
"update_organization": "Actualizar organización",
"team": {
"heading": "Equipo",
"sub_heading": "Configura tu sitio web",
"body": "Agregue compañeros de equipo a su organización para que ambos puedan colaborar en proyectos.",
"button": "Gestionar equipo"
"button": "Gestionar equipo",
"sub_heading": "Configura tu equipo"
},
"custom_domain": {
"heading": "Dominio personalizado",
@@ -1239,7 +1252,10 @@
},
"profile_picture": {
"heading": "Foto de perfil",
"upload_image": "Cargar imagen"
"upload_image": "Cargar imagen",
"file_size": "Tamaño máximo de archivo:",
"accepted": "Aceptado:",
"validation_error": "El tamaño del archivo excede el límite máximo:"
}
},
"tabs": {
@@ -194,7 +194,8 @@
"team_members": "Membres de l'équipe",
"back": "Retour aux paramètres",
"download_lessons": "Mettre à niveau pour télécharger les leçons",
"download_course": "Mettre à niveau pour télécharger le cours"
"download_course": "Mettre à niveau pour télécharger le cours",
"domain": "Mettez à niveau votre forfait pour ajouter des domaines personnalisés"
},
"audience": {
"title": "Public",
@@ -923,12 +924,23 @@
"settings": {
"domains": {
"add": "Ajouter",
"work_together": "Ajoutez vos coéquipiers ou collaborateurs à votre organisation. Commencez à travailler ensemble",
"url": "URL",
"update": "Mettre à jour le domaine",
"custom": "Domaine personnalisé",
"domain": "Ajoutez votre propre nom de domaine",
"title": "Domaine personnalisé"
"title": "Domaine personnalisé",
"save": "Sauvegarder",
"your_domain": "Votre domaine",
"custom_domain_error": "Vous ne pouvez pas ajouter un domaine de premier niveau en tant que domaine personnalisé. Utilisez plutôt un sous-domaine tel que « courses.[votresite Web].com » ou « www.[votre site Web].com ».",
"custom_domain_success": "Domaine personnalisé ajouté avec succès",
"dns_description": "Définissez l'enregistrement suivant sur votre fournisseur DNS pour continuer :",
"dns_type": "Taper",
"dns_value": "Valeur",
"dns_name": "Nom",
"refresh": "Rafraîchir",
"remove": "Retirer",
"custom_favicon": "Icône de favori personnalisée",
"custom_code": "Code personnalisé"
},
"customize-lms": {
"title": "Personnaliser le LMS",
@@ -1084,7 +1096,8 @@
"learn": "Apprendre encore plus",
"month": "mois",
"monthly": "Mensuel",
"annually": "Annuellement"
"annually": "Annuellement",
"save": "Économisez 2 mois"
},
"plan_names": {
"free": "Gratuit",
@@ -1206,9 +1219,9 @@
"update_organization": "Mettre à jour l'organisation",
"team": {
"heading": "Équipe",
"sub_heading": "Configurez votre site Web",
"body": "Ajoutez des coéquipiers à votre organisation afin que vous puissiez tous les deux collaborer sur des projets.",
"button": "Gérer l'équipe"
"button": "Gérer l'équipe",
"sub_heading": "Configurez votre équipe"
},
"custom_domain": {
"heading": "Domaine personnalisé",
@@ -1239,7 +1252,10 @@
},
"profile_picture": {
"heading": "Image de profil",
"upload_image": "Télécharger une image"
"upload_image": "Télécharger une image",
"file_size": "Taille maximale du fichier :",
"accepted": "Accepté:",
"validation_error": "La taille du fichier dépasse la limite maximale :"
}
},
"tabs": {
@@ -194,7 +194,8 @@
"team_members": "टीम के सदस्य",
"back": "सेटिंग्स पर वापस जाएँ",
"download_lessons": "पाठ डाउनलोड करने के लिए अपग्रेड करें",
"download_course": "पाठ्यक्रम डाउनलोड करने के लिए अपग्रेड करें"
"download_course": "पाठ्यक्रम डाउनलोड करने के लिए अपग्रेड करें",
"domain": "कस्टम डोमेन जोड़ने के लिए अपनी योजना को अपग्रेड करें"
},
"audience": {
"title": "श्रोता",
@@ -923,12 +924,23 @@
"settings": {
"domains": {
"add": "जोड़ना",
"work_together": "अपने टीम के साथियों या सहयोगियों को अपने संगठन में जोड़ें। एक साथ काम करना शुरू करें",
"url": "यूआरएल",
"update": "डोमेन अद्यतन करें",
"custom": "कस्टम डोमेन",
"domain": "अपना स्वयं का डोमेन नाम जोड़ें",
"title": "कस्टम डोमेन"
"title": "कस्टम डोमेन",
"save": "बचाना",
"your_domain": "आपका डोमेन",
"custom_domain_error": "आप किसी शीर्ष स्तरीय डोमेन को कस्टम डोमेन के रूप में नहीं जोड़ सकते. इसके बजाय, 'courses.[yourwebsite].com' या 'www.[yourwebsite].com' जैसे उपडोमेन का उपयोग करें।",
"custom_domain_success": "कस्टम डोमेन सफलतापूर्वक जोड़ा गया",
"dns_description": "जारी रखने के लिए अपने DNS प्रदाता पर निम्नलिखित रिकॉर्ड सेट करें:",
"dns_type": "प्रकार",
"dns_value": "कीमत",
"dns_name": "नाम",
"refresh": "ताज़ा करना",
"remove": "निकालना",
"custom_favicon": "कस्टम फ़ेविकॉन",
"custom_code": "कस्टम कोड"
},
"customize-lms": {
"title": "एलएमएस को अनुकूलित करें",
@@ -1084,7 +1096,8 @@
"learn": "और अधिक जानें",
"month": "महीना",
"monthly": "महीने के",
"annually": "हर साल"
"annually": "हर साल",
"save": "2 महीने बचाएं"
},
"plan_names": {
"free": "मुक्त",
@@ -1206,9 +1219,9 @@
"update_organization": "संगठन अद्यतन करें",
"team": {
"heading": "टीम",
"sub_heading": "अपनी वेबसाइट सेट करें",
"body": "अपने संगठन में टीम के साथियों को जोड़ें ताकि आप दोनों परियोजनाओं पर सहयोग कर सकें।",
"button": "टीम का प्रबंधन करें"
"button": "टीम का प्रबंधन करें",
"sub_heading": "अपनी टीम स्थापित करें"
},
"custom_domain": {
"heading": "कस्टम डोमेन",
@@ -1239,7 +1252,10 @@
},
"profile_picture": {
"heading": "प्रोफ़ाइल फोटो",
"upload_image": "तस्विर अपलोड करना"
"upload_image": "तस्विर अपलोड करना",
"file_size": "अधिकतम फ़ाइल आकार:",
"accepted": "स्वीकृत:",
"validation_error": "फ़ाइल का आकार अधिकतम सीमा से अधिक है:"
}
},
"tabs": {
@@ -194,7 +194,8 @@
"team_members": "Membros do time",
"back": "Voltar para configurações",
"download_lessons": "Atualize para baixar lições",
"download_course": "Atualize para baixar o curso"
"download_course": "Atualize para baixar o curso",
"domain": "Atualize seu plano para adicionar domínios personalizados"
},
"audience": {
"title": "Público",
@@ -923,12 +924,23 @@
"settings": {
"domains": {
"add": "Adicionar",
"work_together": "Adicione seus companheiros de equipe ou colaboradores à sua organização. Comece a trabalhar juntos",
"url": "URL",
"update": "Atualizar domínio",
"custom": "Domínio personalizado",
"domain": "Adicione seu próprio nome de domínio",
"title": "Domínio personalizado"
"title": "Domínio personalizado",
"save": "Salvar",
"your_domain": "Seu domínio",
"custom_domain_error": "Você não pode adicionar um domínio de nível superior como domínio personalizado. Em vez disso, use um subdomínio como 'cursos.[seusite].com' ou 'www.[seusite].com'.",
"custom_domain_success": "Domínio personalizado adicionado com sucesso",
"dns_description": "Defina o seguinte registro em seu provedor DNS para continuar:",
"dns_type": "Tipo",
"dns_value": "Valor",
"dns_name": "Nome",
"refresh": "Atualizar",
"remove": "Remover",
"custom_favicon": "Favicon personalizado",
"custom_code": "Código personalizado"
},
"customize-lms": {
"title": "Personalizar LMS",
@@ -1084,7 +1096,8 @@
"learn": "Saber mais",
"month": "mês",
"monthly": "Por mês",
"annually": "Anualmente"
"annually": "Anualmente",
"save": "Economize 2 meses"
},
"plan_names": {
"free": "Livre",
@@ -1206,9 +1219,9 @@
"update_organization": "Atualizar organização",
"team": {
"heading": "Equipe",
"sub_heading": "Configure seu site",
"body": "Adicione colegas de equipe à sua organização para que ambos possam colaborar em projetos.",
"button": "Gerenciar equipe"
"button": "Gerenciar equipe",
"sub_heading": "Monte sua equipe"
},
"custom_domain": {
"heading": "Domínio personalizado",
@@ -1239,7 +1252,10 @@
},
"profile_picture": {
"heading": "Foto do perfil",
"upload_image": "Enviar Imagem"
"upload_image": "Enviar Imagem",
"file_size": "Tamanho máximo do arquivo:",
"accepted": "Aceito:",
"validation_error": "O tamanho do arquivo excede o limite máximo:"
}
},
"tabs": {
@@ -194,7 +194,8 @@
"team_members": "Члены команды",
"back": "Вернуться к настройкам",
"download_lessons": "Обновите, чтобы скачивать уроки",
"download_course": "Обновите, чтобы загрузить курс"
"download_course": "Обновите, чтобы загрузить курс",
"domain": "Обновите свой план, чтобы добавить персональные домены"
},
"audience": {
"title": "Аудитория",
@@ -923,12 +924,23 @@
"settings": {
"domains": {
"add": "Добавлять",
"work_together": "Добавьте своих товарищей по команде или сотрудников в свою организацию. Начните работать вместе",
"url": "URL-адрес",
"update": "Обновить домен",
"custom": "Пользовательский домен",
"domain": "Добавьте свое собственное доменное имя",
"title": "Пользовательский домен"
"title": "Пользовательский домен",
"save": "Сохранять",
"your_domain": "Ваш домен",
"custom_domain_error": "Вы не можете добавить домен верхнего уровня в качестве личного домена. Вместо этого используйте поддомен, например «courses.[вашсайт].com» или «www.[вашсайт].com».",
"custom_domain_success": "Персональный домен успешно добавлен",
"dns_description": "Чтобы продолжить, установите следующую запись у своего DNS-провайдера:",
"dns_type": "Тип",
"dns_value": "Ценить",
"dns_name": "Имя",
"refresh": "Обновить",
"remove": "Удалять",
"custom_favicon": "Пользовательский значок",
"custom_code": "Пользовательский код"
},
"customize-lms": {
"title": "Настроить систему управления обучением",
@@ -1084,7 +1096,8 @@
"learn": "Узнать больше",
"month": "месяц",
"monthly": "Ежемесячно",
"annually": "Ежегодно"
"annually": "Ежегодно",
"save": "Сэкономьте 2 месяца"
},
"plan_names": {
"free": "Бесплатно",
@@ -1206,9 +1219,9 @@
"update_organization": "Обновить организацию",
"team": {
"heading": "Команда",
"sub_heading": "Настройте свой веб-сайт",
"body": "Добавьте коллег в свою организацию, чтобы вы оба могли совместно работать над проектами.",
"button": "Управление командой"
"button": "Управление командой",
"sub_heading": "Создайте свою команду"
},
"custom_domain": {
"heading": "Пользовательский домен",
@@ -1239,7 +1252,10 @@
},
"profile_picture": {
"heading": "Изображение профиля",
"upload_image": "Загрузить изображение"
"upload_image": "Загрузить изображение",
"file_size": "Максимальный размер файла:",
"accepted": "Принял:",
"validation_error": "Размер файла превышает максимальный предел:"
}
},
"tabs": {
@@ -194,7 +194,8 @@
"team_members": "Thành viên của nhóm",
"back": "Quay lại Cài đặt",
"download_lessons": "Nâng cấp để tải bài học",
"download_course": "Nâng cấp để tải xuống khóa học"
"download_course": "Nâng cấp để tải xuống khóa học",
"domain": "Nâng cấp gói của bạn để thêm miền tùy chỉnh"
},
"audience": {
"title": "Khán giả",
@@ -923,12 +924,23 @@
"settings": {
"domains": {
"add": "Thêm vào",
"work_together": "Thêm đồng đội hoặc cộng tác viên vào tổ chức của bạn. Bắt đầu làm việc cùng nhau",
"url": "URL",
"update": "Cập nhật tên miền",
"custom": "Tên miền tùy chọn",
"domain": "Thêm tên miền của riêng bạn",
"title": "Tên miền tùy chọn"
"title": "Tên miền tùy chọn",
"save": "Cứu",
"your_domain": "Tên miền của bạn",
"custom_domain_error": "Bạn không thể thêm miền cấp cao nhất làm miền tùy chỉnh. Thay vào đó, hãy sử dụng tên miền phụ như 'courses.[yourwebsite].com' hoặc 'www.[yourwebsite].com'.",
"custom_domain_success": "Đã thêm miền tùy chỉnh thành công",
"dns_description": "Đặt bản ghi sau trên nhà cung cấp DNS của bạn để tiếp tục:",
"dns_type": "Kiểu",
"dns_value": "Giá trị",
"dns_name": "Tên",
"refresh": "Làm cho khỏe lại",
"remove": "Di dời",
"custom_favicon": "Biểu tượng yêu thích tùy chỉnh",
"custom_code": "Mã tùy chỉnh"
},
"customize-lms": {
"title": "Tùy chỉnh LMS",
@@ -1084,7 +1096,8 @@
"learn": "Tìm hiểu thêm",
"month": "tháng",
"monthly": "hàng tháng",
"annually": "Hàng năm"
"annually": "Hàng năm",
"save": "Tiết kiệm 2 tháng"
},
"plan_names": {
"free": "Miễn phí",
@@ -1206,9 +1219,9 @@
"update_organization": "Cập nhật tổ chức",
"team": {
"heading": "Đội",
"sub_heading": "Thiết lập trang web của bạn",
"body": "Thêm đồng đội vào tổ chức của bạn để cả hai có thể cộng tác trong các dự án.",
"button": "Quản lý nhóm"
"button": "Quản lý nhóm",
"sub_heading": "Thiết lập nhóm của bạn"
},
"custom_domain": {
"heading": "Tên miền tùy chọn",
@@ -1239,7 +1252,10 @@
},
"profile_picture": {
"heading": "Ảnh đại diện",
"upload_image": "Tải hình ảnh lên"
"upload_image": "Tải hình ảnh lên",
"file_size": "Kích thước tệp tối đa:",
"accepted": "Đã chấp nhận:",
"validation_error": "Kích thước tệp vượt quá giới hạn tối đa:"
}
},
"tabs": {
+63
View File
@@ -34,6 +34,10 @@ export interface CurrentOrg {
is_active: boolean;
}[];
is_restricted: boolean;
customDomain?: string;
isCustomDomainVerified?: boolean;
customCode?: string;
favicon?: string;
}
export interface OrgTeamMember {
@@ -53,3 +57,62 @@ export interface OrgAudience {
avatar_url: string;
date_joined: string;
}
export type DomainVerificationStatusProps =
| 'Valid Configuration'
| 'Invalid Configuration'
| 'Pending Verification'
| 'Domain Not Found'
| 'Unknown Error';
// From https://vercel.com/docs/rest-api/endpoints#get-a-project-domain
export interface DomainResponse {
name: string;
apexName: string;
projectId: string;
redirect?: string | null;
redirectStatusCode?: (307 | 301 | 302 | 308) | null;
gitBranch?: string | null;
updatedAt?: number;
createdAt?: number;
/** `true` if the domain is verified for use with the project. If `false` it will not be used as an alias on this project until the challenge in `verification` is completed. */
verified: boolean;
/** A list of verification challenges, one of which must be completed to verify the domain for use on the project. After the challenge is complete `POST /projects/:idOrName/domains/:domain/verify` to verify the domain. Possible challenges: - If `verification.type = TXT` the `verification.domain` will be checked for a TXT record matching `verification.value`. */
verification: {
type: string;
domain: string;
value: string;
reason: string;
}[];
}
// From https://vercel.com/docs/rest-api/endpoints#get-a-domain-s-configuration
export interface DomainConfigResponse {
/** How we see the domain's configuration. - `CNAME`: Domain has a CNAME pointing to Vercel. - `A`: Domain's A record is resolving to Vercel. - `http`: Domain is resolving to Vercel but may be behind a Proxy. - `null`: Domain is not resolving to Vercel. */
configuredBy?: ('CNAME' | 'A' | 'http') | null;
/** Which challenge types the domain can use for issuing certs. */
acceptedChallenges?: ('dns-01' | 'http-01')[];
/** Whether or not the domain is configured AND we can automatically generate a TLS certificate. */
misconfigured: boolean;
}
// From https://vercel.com/docs/rest-api/endpoints#verify-project-domain
export interface DomainVerificationResponse {
name: string;
apexName: string;
projectId: string;
redirect?: string | null;
redirectStatusCode?: (307 | 301 | 302 | 308) | null;
gitBranch?: string | null;
updatedAt?: number;
createdAt?: number;
/** `true` if the domain is verified for use with the project. If `false` it will not be used as an alias on this project until the challenge in `verification` is completed. */
verified: boolean;
/** A list of verification challenges, one of which must be completed to verify the domain for use on the project. After the challenge is complete `POST /projects/:idOrName/domains/:domain/verify` to verify the domain. Possible challenges: - If `verification.type = TXT` the `verification.domain` will be checked for a TXT record matching `verification.value`. */
verification?: {
type: string;
domain: string;
value: string;
reason: string;
}[];
}