1 import { useEffect, useRef } from 'react';
3 import { HTTP_STATUS_CODE } from '@proton/shared/lib/constants';
5 import useApiStatus from './useApiStatus';
7 const useDynamicFavicon = (faviconSrc: string) => {
8 const faviconRef = useRef<string>('');
9 const { offline, apiUnreachable } = useApiStatus();
11 // We can't rely solely on the Boolean offline because browsers may not catch all offline instances properly.
12 // We will get some false positives with the condition below, but that's ok
13 const isPossiblyOffline = offline || !!apiUnreachable;
17 const run = async () => {
18 if (faviconSrc === faviconRef.current) {
19 // no need to update the favicon
22 // Add random param to force refresh
23 const randomParameter = Math.random().toString(36).substring(2);
24 const href = `${faviconSrc}?v=${randomParameter}`;
28 * Proactively fetch favicon to test if /assets are reachable.
29 * * If that goes well, the request is cached and not launched again below when actually changing the favicon in the HTML
30 * * If that doesn't work, we want to handle the error here since we can't attach an error handled to the link tag that controls the favicon
32 const { status } = await fetch(href);
34 if (status !== HTTP_STATUS_CODE.OK) {
35 throw new Error('New favicon was not fetched properly');
38 // if we cannot fetch the favicon, do not attempt to change it
42 // Ensure all favicons are removed, otherwise chrome has trouble updating to the dynamic icon
43 const links = document.querySelectorAll('link[rel="icon"]:not([data-dynamic-favicon])');
44 links.forEach((link) => {
48 const favicon = document.querySelector('link[rel="icon"][type="image/svg+xml"][data-dynamic-favicon]');
51 favicon.setAttribute('href', href);
53 const link = document.createElement('link');
54 link.setAttribute('rel', 'icon');
55 link.setAttribute('type', 'image/svg+xml');
56 link.setAttribute('data-dynamic-favicon', '');
57 link.setAttribute('href', href);
58 document.head.appendChild(link);
60 faviconRef.current = faviconSrc;
65 // isPossiblyOffline is a dependency so that we re-try to update the favicon when going offline and back online
66 [faviconSrc, isPossiblyOffline]
70 export default useDynamicFavicon;