CursosEmpresasBlogLiveConfPrecios

Location y hash navigation

Clase 8 de 17 • Curso de API REST con Javascript: Ejemplos con APIs reales

Clase anteriorSiguiente clase

Contenido del curso

Presentación del proyecto: PlatziMovies
  • 1
    TheMovieDB: análisis de su API

    TheMovieDB: análisis de su API

    07:15
  • 2
    Bocetos en papel y diseño en Figma

    Bocetos en papel y diseño en Figma

    08:05
Configuración inicial y maquetación del proyecto
  • 3
    Configuración del entorno de desarrollo

    Configuración del entorno de desarrollo

    16:53
  • 4
    Maquetación del proyecto: HTML y CSS

    Maquetación del proyecto: HTML y CSS

    18:34
Consumiendo la API
  • 5
    Lista de películas en tendencia

    Lista de películas en tendencia

    16:41
  • 6
    Lista de categorías

    Lista de categorías

    10:32
  • 7
    Migración a Axios

    Migración a Axios

    07:18
Navegación
  • 8
    Location y hash navigation

    Location y hash navigation

    17:17
  • 9
    Mostrando y ocultando secciones

    Mostrando y ocultando secciones

    22:05
  • 10
    Error: carga duplicada de datos

    Error: carga duplicada de datos

    06:30
Views
  • 11
    Filtrando películas por categoría

    Filtrando películas por categoría

    21:38
  • 12
    Retos: scrollTop y DRY

    Retos: scrollTop y DRY

    11:13
  • 13
    Buscador de películas

    Buscador de películas

    11:10
  • 14
    Retos: historial de navegación y página de tendencias

    Retos: historial de navegación y página de tendencias

    06:19
  • 15
    Endpoint de detalles de una película

    Endpoint de detalles de una película

    18:55
  • 16
    Lista de películas recomendadas

    Lista de películas recomendadas

    07:36
Próximos pasos
  • 17
    Toma el Curso Profesional de Consumo de API REST con JavaScript

    Toma el Curso Profesional de Consumo de API REST con JavaScript

    02:19
    Oscar Fuentes Esteves

    Oscar Fuentes Esteves

    student•
    hace 4 años

    Si están usando la extensión live server, deben de tener cuidado de la url que está en el navegador, al cambiar el location.hash manualmente (desde consola) se cambia la ruta en la ventana del navagador también, y si pusieron en consola algo como:

    location.hash="hola"

    y realizan algún cambio en el código, al guardar, la extension live server "refrescará" la ventana del navegador, pero conservando el hash "#hola" en la dirección de la página, lo que puede provocar que creas que tu código está mal, cual en realidad sí está funcionando.

      Juan Castro

      Juan Castro

      teacher•
      hace 4 años

      Ufff, no se me había ocurrido. Muy buen ojo ahí.

      Christian Velázquez

      Christian Velázquez

      student•
      hace 3 años

      Gracias.

    Julian Franco

    Julian Franco

    student•
    hace 4 años

    El

    false

    según la documentación se conoce como

    useCapture

    Es Opcional

    Si es true, useCapture indica que el usuario desea iniciar la captura. Después de iniciar la captura, todos los eventos del tipo especificado serán lanzados al listener registrado antes de comenzar a ser controlados por algún EventTarget que esté por debajo en el arbol DOM del documento.

    https://developer.mozilla.org/es/docs/Web/API/EventTarget/addEventListener

    Adicional en la parte que menciona el:

    load

    Este cuenta con una caracteristica vs el DOMContentLoaded

    El evento load se desencadena cuando se ha cargado toda la página, incluidos todos los recursos dependientes, como hojas de estilo e imágenes. Esto contrasta con DOMContentLoaded, que se activa tan pronto como se ha cargado el DOM de la página, sin esperar a que los recursos terminen de cargarse.

    https://developer.mozilla.org/en-US/docs/Web/API/Window/load_event

    Se que escribi mucho perdón, Pero si declaran la funcion como arrow function de la siguiente manera

    window.addEventListener('DOMContentLoaded', navigatior, false) window.addEventListener('hashchange', navigatior, false) const navigatior = () => { //your code }

    Les va a generar un error interesante 😏

      Juan Castro

      Juan Castro

      teacher•
      hace 4 años

      :clap:

      Raycris Maldonado

      Raycris Maldonado

      student•
      hace 3 años

      Grande amigo, me estaba dando el error por tener el arrow function!

    Jose Castillo

    Jose Castillo

    student•
    hace 3 años

    En videos anteriores hicieron un aporte para optimizar el código y no tener que andar escribiendo a cada rato la linea de .querySelector cuando necesitamos hacer target a un elemento del html.

    En esto me base para ahorrar lineas de código e implementar la misma idea pero con el .createElement que usamos muy seguido.

    const Cr = (elemento) => document.createElement(elemento);

    Utilice Cr por ser las siglas de la palabra "Create", pero pueden nombrarla del modo que quieran, de este modo cada vez que necesitemos crear un elemento por medio de Js Solo tendríamos que escribirlo así:

    const parrafo = Cr('p');
      Paula Inés Cudicio

      Paula Inés Cudicio

      student•
      hace 3 años

      Buenísimo!! no había visto el otro comentario, asique me viene muy bien. Gracias!!!

      Ricardo Alfonso Chavez Vilcapoma

      Ricardo Alfonso Chavez Vilcapoma

      student•
      hace 3 años

      Creo que una vez trataron de hacer lo mismo con console.log y el prof Juan dijo que era un error gravísimo y una mala práctica.

    CRISTIAN DARIO AGUDELO PORRAS

    CRISTIAN DARIO AGUDELO PORRAS

    student•
    hace 2 años

    Esta es mi solucion para evitar anidar tantos if y que ademas me parece mas pulida y facil de leer y entender

    navigator.PNG
      Frandel Corporan Rodríguez

      Frandel Corporan Rodríguez

      student•
      hace 2 años

      Epic👌

      Henry Alexander Velásquez Rosas

      Henry Alexander Velásquez Rosas

      student•
      hace 2 años

      Cool

    Angel Hernandez

    Angel Hernandez

    student•
    hace 4 años

    No es película pero si es documental, por si les interesa: El viaje interminable

    Elber Liebermen

    Elber Liebermen

    student•
    hace 4 años
    • ++Location++ Propiedad del navegador de JS que permite leer la URL en la que nos encontramos actualmente, entre sus propiedades está el hash, puerto, ruta, etc

    • ++onhaschange:++ Permite que ejecutemos cierto código cada vez que cambie nuestro hash

    Orangel Jose Gonzalez Urbina

    Orangel Jose Gonzalez Urbina

    student•
    hace 4 años

    Codigo de la clase 😁👍🏻

    window.addEventListener("DOMContentLoaded", navigator, false) window.addEventListener("hashchange", navigator, false) function navigator() { if (location.hash.startsWith("#trends")) { trendsPage() } else if (location.hash.startsWith("#search=")) { searchPage() } else if (location.hash.startsWith("#movie=")) { movieDetailsPage() } else if (location.hash.startsWith("#category=")) { categoriesPage() } else { homePage() } } function homePage() { console.log("Home!!") getTrendingMoviesPreview() getCategoriesPreview() } function categoriesPage() { console.log("Categories!!") } function movieDetailsPage() { console.log("Movie!!") } function searchPage() { console.log("Search!!") } function trendsPage() { console.log("TRENDS!!") }
    Axel Enrique Galeed Gutierrez

    Axel Enrique Galeed Gutierrez

    student•
    hace 3 años

    Les comparto una forma que encontré para facilitar la lectura del código. :D

    code.png

    const navegador = () => { console.log({ location }); const HASHES = { '#trends' : () => trendsPage(), '#search=' : () => searchPage(), '#movie=' : () => moviePage(), '#category=' : () => categoryPage(), }; for (const KEY of Object.keys(HASHES)) { if (location.hash.startsWith(KEY)) { HASHES[KEY](); return; } } homePage(); }; const homePage = () => { console.log('HOME'); }; const categoryPage = () => { console.log('CATEGORY 37'); }; const moviePage = () => { console.log('MOVIE'); }; const searchPage = () => { console.log('SEARCH'); }; const trendsPage = () => { console.log('TRENDS'); }; window.addEventListener('load', navegador, false); window.addEventListener('hashchange', navegador, false);
      Juan Castro

      Juan Castro

      teacher•
      hace 3 años

      Fuaaaa me encanta la función de navegador!!!

      Génesis Jarlenis Patiño Ynfante

      Génesis Jarlenis Patiño Ynfante

      student•
      hace 3 años

      Me gustó mucho tu código, Galeed. Lo tomé como ejemplo. Yo en lugar de usar for of, usé for in e iteré directamente sobre la key. Gracias!!

    Cesidio Antonio Di Benedetto Carri

    Cesidio Antonio Di Benedetto Carri

    student•
    hace 3 años

    El tercer parametro se utiliza para determinar si se va a manejar con bubbling cuando es false o capturing cuando es true

      Juan Castro

      Juan Castro

      teacher•
      hace 3 años

      ¡Super! Pero ¿qué significa "bubbling"? :eyes:

      Patricia Julliete Rangel Mujica

      Patricia Julliete Rangel Mujica

      student•
      hace 2 años

      el bubbling es la manera de como se propagan los eventos. Desde el elemento hijo, subiendo hasta todos sus padres...

    Jose Angel Morales Gonzalez

    Jose Angel Morales Gonzalez

    student•
    hace 3 años

    Para quien se pregunte como puede hacer más leíble el nido de if else:

    window.addEventListener('load', handleRouter, false) window.addEventListener('hashchange', handleRouter, false) function navigator(){ const router = { '#trends': () => {console.log('trends')}, '#search=': () => {console.log('search')}, '#movie=': () => {console.log('movies')}, '#category=': () => {console.log('categories')}, '#home': () => {console.log('home')}, } if(true){ return router[window.location.hash] || router['#home'] } } function handleRouter(){ const router = navigator() router() }

    De hecho me lo enseño juan dc en otro curso.

      Jose Angel Morales Gonzalez

      Jose Angel Morales Gonzalez

      student•
      hace 3 años

      El if(true) no es necesario

      Andrés Aguirre

      Andrés Aguirre

      student•
      hace 3 años

      Me parece interesante utilizar llave y valor para hacer el routing de los endpoints, sin embargo, el problema de esto es que si el hash no es igual a la llave, no lo va a identificar por lo cual no ejecutaria el codigo que quisieramos, y como estamos usando queryParameters esto pasaria muy seguido.

      Por ejemplo, si el hash fuera '#search=123', el codigo no estaria tomandolo como '#search' ya que no son iguales, por lo cual devolveria 'router['#home']'

      Lo del los objetos con llave y valor serian más utiles cuando sabemos que los endpoints no van a cambiar ó si vamos a hacer más validaciones para que los valores que recibamos como parametros coincidan con las llaves del router.

    Kevin Daniel Hincapie Lumbaque

    Kevin Daniel Hincapie Lumbaque

    student•
    hace 3 años

    Tal vez no les importe mucho pero estaba leyendo la documentacion del evento 'DOMContentLoaded' y dice que este no espera a que todo cargue: " It doesn't wait for other things like images, subframes, and async scripts to finish loading." No espera la carga de imagenes, subframes(no se que son) y scrips asincronos.

    En cambio el evento "load": " should be used only to detect a fully-loaded page" se usa para detectar paginas completamente cargadas.

    Ademas dice que el objetivo de este evento es el Document pero que se usa sobre el windo para manejar el evento en fase de captura o burbuja: "The original target for this event is the Document that has loaded. You can listen for this event on the Window interface to handle it in the capture or bubbling phases."

    Lo de las fases lo explico bastante bien un compañero en estos comentarios. link info

    Arlen Elian Ruiz Pedraza

    Arlen Elian Ruiz Pedraza

    student•
    hace 4 años

    Dejo la documentación sobre el addEventListener en este link

    Victor Hugo Cruz Carballo

    Victor Hugo Cruz Carballo

    student•
    hace 3 años

    Como mensiono Juan tambien en el evento de carga tambien funciona con 'load' pero hay un pequeño problema, cuando cambias el hash no te va a redirecionar sino que se quedara en la misma pantalla. Asi que tenemos que utilizar en el argumento 'DOMContentLoaded'

    Maurizio Alejandro Iglesias Fernandez

    Maurizio Alejandro Iglesias Fernandez

    student•
    hace 2 años

    Me ando muriendo de risa por el "PUMM" del minuto 16:27 JAJAJJAJAJA

    Por cierto, asi va mi proyecto

    TheMovieApp.PNG
      Juan Castro

      Juan Castro

      teacher•
      hace 2 años

      Love it! Al final del curso comparte tu repo :)

    Luis Torres

    Luis Torres

    student•
    hace 3 años

    Vengo del futuro, ya hice mi deploy del proyecto pero mi sorpresa fue que el location.hash = windows.history.back(); NO funciona en cualquier dispositivo de Apple sin importar el navegador...

    Hice el intento con location.href, pero al hacer el history.back() me manda a undefined.

    He buscado soluciones en Google pero no logro dar con ella.

    ¿Alguien tiene alguna idea?

      Juan Castro

      Juan Castro

      teacher•
      hace 3 años

      Hmmmm... Qué extraño, parece que history.back tiene muy buen soporte en prácticamente todos los navegadores, mira: https://developer.mozilla.org/en-US/docs/Web/API/History/back#browser_compatibility

      Rodrigo Andre Gutierrez

      Rodrigo Andre Gutierrez

      student•
      hace 3 años

      windows.history.back() o window.history.back()? ojo

    Jhojan Alberto Tobón Monsalve

    Jhojan Alberto Tobón Monsalve

    student•
    hace 3 años

    En resumen hay dos formas de propagación en el DOM bubbling=false y capturing=true. Si se quiere que el evento de un elemento dentro de otro elemento con evento se ejecute primero, entonces se utiliza false o no se coloca nada porque por defecto es false, pero si se quiere que el evento del elemento externo se ejecute primero que el elemento con el evento interno se utiliza true.

    Sergio Javier Lopez Olivera

    Sergio Javier Lopez Olivera

    student•
    hace 3 años

    El evento 'hashchange' tiene un valor booleano al final para determinar si la navegación es un fragmento o no. Una navegación por fragmentos ocurre cuando la parte de la URL correspondiente al '#' ha cambiado y el valor booleano será cambiado a 'true' si la navegación es una navegación por fragmentos, y 'false' si no lo es. . Básicamente te permite lograr eventos por cambios en el anchor (#) haciendo el sitio dinámico. Esto podría servir por ejemplo para hacer toggle a las clases de tus etiquetas HTML con JS para así mostrar u ocultar distintas vistas.

    N40 M10

    N40 M10

    student•
    hace 2 años

    Deberían de hacer un curso en donde se separe la teoría de localStorage, location y otros elementos, así quedarían mucho más claros, de paso que ese curso también tenga a las API Web más útiles.

    En este curso, al tener que detenerse al explicar de manera superficial ciertos conceptos, por un lado, provoca que sea más lento y, por otro lado, no se profundiza lo suficiente en ciertos conceptos, pues solo se limitan a que el ejercicio funcione, pero no a que un estudiante pueda aplicar lo que quiera con esos conceptos.

    Generalmente, eso le pasa al grupo que desarrollo este curso en otros mas.

    Henry Alexander Velásquez Rosas

    Henry Alexander Velásquez Rosas

    student•
    hace 2 años

    Auto Save de VSC 🔥

    Si te olvidas con frecuencia de guardar los cambios de tus archivos puedes usar el autoguardado de VSC que lo hará automáticamente por ti.

    Solo ve a File y luego dale check en Auto Save

    Xavier Flores

    Xavier Flores

    student•
    hace 2 años

    de lo aprendido en otro curso lo correcto sería escribirlo así:

    const navigator = () => { console.log({ location }); if (location.hash.startsWith('#trends')) { trendPage(); } else if (location.hash.startsWith('#search=')) { searchPage(); } else if (location.hash.startsWith('#movie=')) { movieDetailsPage(); } else if (location.hash.startsWith('#category=')) { categoriesPage(); } else { homePage(); } location.hash } window.addEventListener('DOMContentLoaded', navigator, false); window.addEventListener('haschange', navigator, false);

    Cuando se trabaja con eventListener lo recomendable es colocar nuestra funcion con un arrow function (en este caso "navigator" debido a que si en un futuro necesitemos eleminar ese evento lo podriamos ubicar con su nombre "navigator" y optimizar el performance de nuestro DOM.

Escuelas

  • Desarrollo Web
    • Fundamentos del Desarrollo Web Profesional
    • Diseño y Desarrollo Frontend
    • Desarrollo Frontend con JavaScript
    • Desarrollo Frontend con Vue.js
    • Desarrollo Frontend con Angular
    • Desarrollo Frontend con React.js
    • Desarrollo Backend con Node.js
    • Desarrollo Backend con Python
    • Desarrollo Backend con Java
    • Desarrollo Backend con PHP
    • Desarrollo Backend con Ruby
    • Bases de Datos para Web
    • Seguridad Web & API
    • Testing Automatizado y QA para Web
    • Arquitecturas Web Modernas y Escalabilidad
    • DevOps y Cloud para Desarrolladores Web
  • English Academy
    • Inglés Básico A1
    • Inglés Básico A2
    • Inglés Intermedio B1
    • Inglés Intermedio Alto B2
    • Inglés Avanzado C1
    • Inglés para Propósitos Específicos
    • Inglés de Negocios
  • Marketing Digital
    • Fundamentos de Marketing Digital
    • Marketing de Contenidos y Redacción Persuasiva
    • SEO y Posicionamiento Web
    • Social Media Marketing y Community Management
    • Publicidad Digital y Paid Media
    • Analítica Digital y Optimización (CRO)
    • Estrategia de Marketing y Growth
    • Marketing de Marca y Comunicación Estratégica
    • Marketing para E-commerce
    • Marketing B2B
    • Inteligencia Artificial Aplicada al Marketing
    • Automatización del Marketing
    • Marca Personal y Marketing Freelance
    • Ventas y Experiencia del Cliente
    • Creación de Contenido para Redes Sociales
  • Inteligencia Artificial y Data Science
    • Fundamentos de Data Science y AI
    • Análisis y Visualización de Datos
    • Machine Learning y Deep Learning
    • Data Engineer
    • Inteligencia Artificial para la Productividad
    • Desarrollo de Aplicaciones con IA
    • AI Software Engineer
  • Ciberseguridad
    • Fundamentos de Ciberseguridad
    • Hacking Ético y Pentesting (Red Team)
    • Análisis de Malware e Ingeniería Forense
    • Seguridad Defensiva y Cumplimiento (Blue Team)
    • Ciberseguridad Estratégica
  • Liderazgo y Habilidades Blandas
    • Fundamentos de Habilidades Profesionales
    • Liderazgo y Gestión de Equipos
    • Comunicación Avanzada y Oratoria
    • Negociación y Resolución de Conflictos
    • Inteligencia Emocional y Autogestión
    • Productividad y Herramientas Digitales
    • Gestión de Proyectos y Metodologías Ágiles
    • Desarrollo de Carrera y Marca Personal
    • Diversidad, Inclusión y Entorno Laboral Saludable
    • Filosofía y Estrategia para Líderes
  • Diseño de Producto y UX
    • Fundamentos de Diseño UX/UI
    • Investigación de Usuarios (UX Research)
    • Arquitectura de Información y Usabilidad
    • Diseño de Interfaces y Prototipado (UI Design)
    • Sistemas de Diseño y DesignOps
    • Redacción UX (UX Writing)
    • Creatividad e Innovación en Diseño
    • Diseño Accesible e Inclusivo
    • Diseño Asistido por Inteligencia Artificial
    • Gestión de Producto y Liderazgo en Diseño
    • Diseño de Interacciones Emergentes (VUI/VR)
    • Desarrollo Web para Diseñadores
    • Diseño y Prototipado No-Code
  • Contenido Audiovisual
    • Fundamentos de Producción Audiovisual
    • Producción de Video para Plataformas Digitales
    • Producción de Audio y Podcast
    • Fotografía y Diseño Gráfico para Contenido Digital
    • Motion Graphics y Animación
    • Contenido Interactivo y Realidad Aumentada
    • Estrategia, Marketing y Monetización de Contenidos
  • Desarrollo Móvil
    • Fundamentos de Desarrollo Móvil
    • Desarrollo Nativo Android con Kotlin
    • Desarrollo Nativo iOS con Swift
    • Desarrollo Multiplataforma con React Native
    • Desarrollo Multiplataforma con Flutter
    • Arquitectura y Patrones de Diseño Móvil
    • Integración de APIs y Persistencia Móvil
    • Testing y Despliegue en Móvil
    • Diseño UX/UI para Móviles
  • Diseño Gráfico y Arte Digital
    • Fundamentos del Diseño Gráfico y Digital
    • Diseño de Identidad Visual y Branding
    • Ilustración Digital y Arte Conceptual
    • Diseño Editorial y de Empaques
    • Motion Graphics y Animación 3D
    • Diseño Gráfico Asistido por Inteligencia Artificial
    • Creatividad e Innovación en Diseño
  • Programación
    • Fundamentos de Programación e Ingeniería de Software
    • Herramientas de IA para el trabajo
    • Matemáticas para Programación
    • Programación con Python
    • Programación con JavaScript
    • Programación con TypeScript
    • Programación Orientada a Objetos con Java
    • Desarrollo con C# y .NET
    • Programación con PHP
    • Programación con Go y Rust
    • Programación Móvil con Swift y Kotlin
    • Programación con C y C++
    • Administración Básica de Servidores Linux
  • Negocios
    • Fundamentos de Negocios y Emprendimiento
    • Estrategia y Crecimiento Empresarial
    • Finanzas Personales y Corporativas
    • Inversión en Mercados Financieros
    • Ventas, CRM y Experiencia del Cliente
    • Operaciones, Logística y E-commerce
    • Gestión de Proyectos y Metodologías Ágiles
    • Aspectos Legales y Cumplimiento
    • Habilidades Directivas y Crecimiento Profesional
    • Diversidad e Inclusión en el Entorno Laboral
    • Herramientas Digitales y Automatización para Negocios
  • Blockchain y Web3
    • Fundamentos de Blockchain y Web3
    • Desarrollo de Smart Contracts y dApps
    • Finanzas Descentralizadas (DeFi)
    • NFTs y Economía de Creadores
    • Seguridad Blockchain
    • Ecosistemas Blockchain Alternativos (No-EVM)
    • Producto, Marketing y Legal en Web3
  • Recursos Humanos
    • Fundamentos y Cultura Organizacional en RRHH
    • Atracción y Selección de Talento
    • Cultura y Employee Experience
    • Gestión y Desarrollo de Talento
    • Desarrollo y Evaluación de Liderazgo
    • Diversidad, Equidad e Inclusión
    • AI y Automatización en Recursos Humanos
    • Tecnología y Automatización en RRHH
  • Finanzas e Inversiones
    • Fundamentos de Finanzas Personales y Corporativas
    • Análisis y Valoración Financiera
    • Inversión y Mercados de Capitales
    • Finanzas Descentralizadas (DeFi) y Criptoactivos
    • Finanzas y Estrategia para Startups
    • Inteligencia Artificial Aplicada a Finanzas
    • Domina Excel
    • Financial Analyst
    • Conseguir trabajo en Finanzas e Inversiones
  • Startups
    • Fundamentos y Validación de Ideas
    • Estrategia de Negocio y Product-Market Fit
    • Desarrollo de Producto y Operaciones Lean
    • Finanzas, Legal y Fundraising
    • Marketing, Ventas y Growth para Startups
    • Cultura, Talento y Liderazgo
    • Finanzas y Operaciones en Ecommerce
    • Startups Web3 y Blockchain
    • Startups con Impacto Social
    • Expansión y Ecosistema Startup
  • Cloud Computing y DevOps
    • Fundamentos de Cloud y DevOps
    • Administración de Servidores Linux
    • Contenerización y Orquestación
    • Infraestructura como Código (IaC) y CI/CD
    • Amazon Web Services
    • Microsoft Azure
    • Serverless y Observabilidad
    • Certificaciones Cloud (Preparación)
    • Plataforma Cloud GCP

Platzi y comunidad

  • Platzi Business
  • Live Classes
  • Lanzamientos
  • Executive Program
  • Trabaja con nosotros
  • Podcast

Recursos

  • Manual de Marca

Soporte

  • Preguntas Frecuentes
  • Contáctanos

Legal

  • Términos y Condiciones
  • Privacidad
  • Tyc promociones
Reconocimientos
Reconocimientos
Logo reconocimientoTop 40 Mejores EdTech del mundo · 2024
Logo reconocimientoPrimera Startup Latina admitida en YC · 2014
Logo reconocimientoPrimera Startup EdTech · 2018
Logo reconocimientoCEO Ganador Medalla por la Educación T4 & HP · 2024
Logo reconocimientoCEO Mejor Emprendedor del año · 2024
De LATAM conpara el mundo
YoutubeInstagramLinkedInTikTokFacebookX (Twitter)Threads