import variables from 'modules/variables'; import { PureComponent, createRef } from 'react'; import { MdContentCopy, MdStarBorder, MdStar, MdPerson, MdOpenInNew, MdIosShare, } from 'react-icons/md'; import { toast } from 'react-toastify'; import Tooltip from '../../helpers/tooltip/Tooltip'; import Modal from 'react-modal'; import ShareModal from '../../helpers/sharemodal/ShareModal'; import offline_quotes from './offline_quotes.json'; import EventBus from 'modules/helpers/eventbus'; import './quote.scss'; export default class Quote extends PureComponent { buttons = { share: ( ), copy: ( ), unfavourited: ( ), favourited: ( ), }; constructor() { super(); this.state = { quote: '', author: '', authorOccupation: '', favourited: this.useFavourite(), share: localStorage.getItem('quoteShareButton') === 'false' ? null : this.buttons.share, copy: localStorage.getItem('copyButton') === 'false' ? null : this.buttons.copy, quoteLanguage: '', type: localStorage.getItem('quoteType') || 'api', shareModal: false, }; this.quote = createRef(); this.quotediv = createRef(); this.quoteauthor = createRef(); } useFavourite() { if (localStorage.getItem('favouriteQuoteEnabled') === 'true') { return localStorage.getItem('favouriteQuote') ? this.buttons.favourited : this.buttons.unfavourited; } else { return null; } } doOffline() { // Get a random quote from our local JSON const quote = offline_quotes[Math.floor(Math.random() * offline_quotes.length)]; this.setState({ quote: '"' + quote.quote + '"', author: quote.author, authorlink: this.getAuthorLink(quote.author), authorimg: '', }); } getAuthorLink(author) { return localStorage.getItem('authorLink') === 'false' || author === 'Unknown' ? null : `https://${variables.languagecode.split('_')[0]}.wikipedia.org/wiki/${author .split(' ') .join('_')}`; } async getAuthorImg(author) { if (localStorage.getItem('authorImg') === 'false') { return { authorimg: null, authorimglicense: null, }; } const authorimgdata = await ( await fetch( `https://${ variables.languagecode.split('_')[0] }.wikipedia.org/w/api.php?action=query&titles=${author}&origin=*&prop=pageimages&format=json&pithumbsize=100`, ) ).json(); let authorimg, authorimglicense; try { authorimg = authorimgdata.query.pages[Object.keys(authorimgdata.query.pages)[0]].thumbnail.source; const authorimglicensedata = await ( await fetch( `https://${ variables.languagecode.split('_')[0] }.wikipedia.org/w/api.php?action=query&prop=imageinfo&iiprop=extmetadata&titles=File:${ authorimgdata.query.pages[Object.keys(authorimgdata.query.pages)[0]].pageimage }&origin=*&format=json`, ) ).json(); const metadata = authorimglicensedata.query.pages[Object.keys(authorimglicensedata.query.pages)[0]] .imageinfo[0].extmetadata; const license = metadata.LicenseShortName; const photographer = metadata.Attribution.value || metadata.Artist?.value.match(/(?.+)<\/a>/i)?.groups.name || 'Unknown'; authorimglicense = `© ${photographer}. ${license.value}`; authorimglicense = authorimglicense.replace(/copyright\s/i, '').replace(/©\s©\s/, '© '); if (license.value === 'Public domain') { authorimglicense = null; } else if (photographer.value === 'Unknown' || !photographer) { authorimglicense = null; authorimg = null; } } catch (e) { authorimg = null; authorimglicense = null; } if (author === 'Unknown') { authorimg = null; authorimglicense = null; } return { authorimg, authorimglicense, }; } async getQuote() { const offline = localStorage.getItem('offlineMode') === 'true'; const favouriteQuote = localStorage.getItem('favouriteQuote'); if (favouriteQuote) { let author = favouriteQuote.split(' - ')[1]; const authorimgdata = await this.getAuthorImg(author); return this.setState({ quote: favouriteQuote.split(' - ')[0], author, authorlink: this.getAuthorLink(author), authorimg: authorimgdata.authorimg, authorimglicense: authorimgdata.authorimglicense, }); } switch (this.state.type) { case 'custom': let customQuote; try { customQuote = JSON.parse(localStorage.getItem('customQuote')); } catch (e) { // move to new format customQuote = [ { quote: localStorage.getItem('customQuote'), author: localStorage.getItem('customQuoteAuthor'), }, ]; localStorage.setItem('customQuote', JSON.stringify(customQuote)); } // pick random customQuote = customQuote ? customQuote[Math.floor(Math.random() * customQuote.length)] : null; if (customQuote !== undefined) { return this.setState({ quote: '"' + customQuote.quote + '"', author: customQuote.author, authorlink: this.getAuthorLink(customQuote.author), authorimg: await this.getAuthorImg(customQuote.author), noQuote: false, }); } else { this.setState({ noQuote: true, }); } break; case 'quote_pack': if (offline) { return this.doOffline(); } const quotePack = []; const installed = JSON.parse(localStorage.getItem('installed')); installed.forEach((item) => { if (item.type === 'quotes') { const quotes = item.quotes.map((quote) => ({ ...quote, fallbackauthorimg: item.icon_url, })); quotePack.push(...quotes); } }); if (quotePack) { const data = quotePack[Math.floor(Math.random() * quotePack.length)]; return this.setState({ quote: '"' + data.quote + '"', author: data.author, authorlink: this.getAuthorLink(data.author), authorimg: data.fallbackauthorimg, }); } else { return this.doOffline(); } case 'api': if (offline) { return this.doOffline(); } // First we try and get a quote from the API... try { const quotelanguage = localStorage.getItem('quotelanguage'); const data = await ( await fetch(variables.constants.API_URL + '/quotes/random?language=' + quotelanguage) ).json(); // If we hit the ratelimit, we fall back to local quotes if (data.statusCode === 429) { return this.doOffline(); } const authorimgdata = await this.getAuthorImg(data.author); const object = { quote: '"' + data.quote.replace(/\s+$/g, '') + '"', author: data.author, authorlink: this.getAuthorLink(data.author), authorimg: authorimgdata.authorimg, authorimglicense: authorimgdata.authorimglicense, quoteLanguage: quotelanguage, authorOccupation: data.author_occupation, }; this.setState(object); localStorage.setItem('currentQuote', JSON.stringify(object)); } catch (e) { // ...and if that fails we load one locally this.doOffline(); } break; default: break; } } copyQuote() { variables.stats.postEvent('feature', 'Quote copied'); navigator.clipboard.writeText(`${this.state.quote} - ${this.state.author}`); toast(variables.getMessage('toasts.quote')); } tweetQuote() { variables.stats.postEvent('feature', 'Quote tweet'); window .open( `https://twitter.com/intent/tweet?text=${this.state.quote} - ${this.state.author} on @getmue`, '_blank', ) .focus(); } favourite() { if (localStorage.getItem('favouriteQuote')) { localStorage.removeItem('favouriteQuote'); this.setState({ favourited: this.buttons.unfavourited, }); } else { localStorage.setItem('favouriteQuote', this.state.quote + ' - ' + this.state.author); this.setState({ favourited: this.buttons.favourited, }); } variables.stats.postEvent('feature', 'Quote favourite'); } init() { this.setZoom(); const quoteType = localStorage.getItem('quoteType'); if ( this.state.type !== quoteType || localStorage.getItem('quotelanguage') !== this.state.quoteLanguage || (quoteType === 'custom' && this.state.quote !== localStorage.getItem('customQuote')) || (quoteType === 'custom' && this.state.author !== localStorage.getItem('customQuoteAuthor')) ) { this.getQuote(); } } setZoom() { const zoomQuote = Number((localStorage.getItem('zoomQuote') || 100) / 100); this.quote.current.style.fontSize = `${0.8 * zoomQuote}em`; this.quoteauthor.current.style.fontSize = `${0.9 * zoomQuote}em`; } componentDidMount() { const test = localStorage.getItem('quotechange'); this.interval = setInterval(() => { if (test !== null) { const targetTime = Number( Number(localStorage.getItem('quoteStartTime')) + Number(localStorage.getItem('quotechange')), ); const currentTime = Number(Date.now()); if (currentTime >= targetTime) { this.setZoom(); this.getQuote(); localStorage.setItem('quoteStartTime', Date.now()); } else { console.log(localStorage.getItem('quotechange')); try { this.setState(JSON.parse(localStorage.getItem('currentQuote'))); } catch (e) { this.setZoom(); this.getQuote(); } } } }); EventBus.on('refresh', (data) => { if (data === 'quote') { if (localStorage.getItem('quote') === 'false') { return (this.quotediv.current.style.display = 'none'); } this.quotediv.current.style.display = 'block'; this.init(); // buttons hot reload this.setState({ favourited: this.useFavourite(), share: localStorage.getItem('quoteShareButton') === 'false' ? null : this.buttons.share, copy: localStorage.getItem('copyButton') === 'false' ? null : this.buttons.copy, }); } // uninstall quote pack reverts the quote to what you had previously if (data === 'marketplacequoteuninstall') { this.init(); } if (data === 'quoterefresh') { this.getQuote(); } }); if ( localStorage.getItem('quotechange') === 'refresh' || localStorage.getItem('quotechange') === null ) { this.setZoom(); this.getQuote(); localStorage.setItem('quoteStartTime', Date.now()); } } componentWillUnmount() { EventBus.off('refresh'); clearInterval(this.interval); } render() { if (this.state.noQuote === true) { return <>; } return (
this.setState({ shareModal: false })} > this.setState({ shareModal: false })} /> {this.state.quote} {localStorage.getItem('widgetStyle') === 'legacy' ? ( <>

{this.state.author}

{this.state.copy} {this.state.share} {this.state.favourited}
) : (
{this.state.authorimg === undefined || this.state.authorimg ? '' : }
{this.state.author !== '' ? (
{this.state.author} {this.state.authorOccupation !== 'Unknown' ? ( {this.state.authorOccupation} ) : null} {this.state.authorimglicense ? this.state.authorimglicense.replace(' undefined. ', ' ') : null}
) : (
{/* these are placeholders for skeleton and as such don't need translating */} loading loading
)}
{this.state.authorOccupation !== 'Unknown' && this.state.authorlink !== '' ? ( {' '} ) : null} {this.state.copy} {this.state.share} {this.state.favourited}
)}
); } }