mirror of https://gitlab.com/ecentrics/concordia
Apostolos Fanakis
4 years ago
8 changed files with 264 additions and 2 deletions
@ -0,0 +1,151 @@ |
|||
import React, { |
|||
useCallback, useMemo, useState, |
|||
useEffect, |
|||
} from 'react'; |
|||
import { |
|||
Button, Form, Input, Modal, |
|||
} from 'semantic-ui-react'; |
|||
import PropTypes from 'prop-types'; |
|||
import { useTranslation } from 'react-i18next'; |
|||
import { useSelector } from 'react-redux'; |
|||
import purgeIndexedDBs from '../../utils/indexedDB/indexedDBUtils'; |
|||
|
|||
const ClearDatabasesModal = (props) => { |
|||
const { |
|||
open, onDatabasesCleared, onCancel, |
|||
} = props; |
|||
const [confirmationInput, setConfirmationInput] = useState(''); |
|||
const [userConfirmed, setUserConfirmed] = useState(false); |
|||
const [isClearing, setIsClearing] = useState(false); |
|||
const user = useSelector((state) => state.user); |
|||
const { t } = useTranslation(); |
|||
|
|||
useEffect(() => { |
|||
if (user.hasSignedUp && confirmationInput === user.username) { |
|||
setUserConfirmed(true); |
|||
} else if (!user.hasSignedUp && confirmationInput === 'concordia') { |
|||
setUserConfirmed(true); |
|||
} else { |
|||
setUserConfirmed(false); |
|||
} |
|||
}, [confirmationInput, user.hasSignedUp, user.username]); |
|||
|
|||
const handleSubmit = useCallback(() => { |
|||
setIsClearing(true); |
|||
|
|||
purgeIndexedDBs() |
|||
.then(() => { |
|||
onDatabasesCleared(); |
|||
}).catch((reason) => console.log(reason)); |
|||
}, [onDatabasesCleared]); |
|||
|
|||
const onCancelTry = useCallback(() => { |
|||
if (!isClearing) { |
|||
setConfirmationInput(''); |
|||
onCancel(); |
|||
} |
|||
}, [isClearing, onCancel]); |
|||
|
|||
const handleInputChange = (event, { value }) => { setConfirmationInput(value); }; |
|||
|
|||
const modalContent = useMemo(() => { |
|||
if (isClearing) { |
|||
return ( |
|||
<> |
|||
<p> |
|||
{t('clear.databases.modal.clearing.progress.message')} |
|||
</p> |
|||
</> |
|||
); |
|||
} |
|||
|
|||
if (user.hasSignedUp) { |
|||
return ( |
|||
<> |
|||
<p> |
|||
{t('clear.databases.modal.description.pre')} |
|||
</p> |
|||
<p> |
|||
{t('clear.databases.modal.description.body.user')} |
|||
</p> |
|||
<Form> |
|||
<Form.Field> |
|||
<label htmlFor="form-clear-databases-field-confirm"> |
|||
{t('clear.databases.modal.form.username.label.user')} |
|||
</label> |
|||
<Input |
|||
id="form-clear-databases-field-confirm" |
|||
name="confirmationInput" |
|||
value={confirmationInput} |
|||
onChange={handleInputChange} |
|||
/> |
|||
</Form.Field> |
|||
</Form> |
|||
</> |
|||
); |
|||
} |
|||
|
|||
return ( |
|||
<> |
|||
<p> |
|||
{t('clear.databases.modal.description.pre')} |
|||
</p> |
|||
<Form> |
|||
<Form.Field> |
|||
<label htmlFor="form-clear-databases-field-confirm"> |
|||
{t('clear.databases.modal.form.username.label.guest')} |
|||
</label> |
|||
<Input |
|||
id="form-clear-databases-field-confirm" |
|||
name="confirmationInput" |
|||
value={confirmationInput} |
|||
onChange={handleInputChange} |
|||
/> |
|||
</Form.Field> |
|||
</Form> |
|||
</> |
|||
); |
|||
}, [confirmationInput, isClearing, t, user.hasSignedUp]); |
|||
|
|||
return useMemo(() => ( |
|||
<Modal |
|||
onClose={onCancelTry} |
|||
open={open} |
|||
size="small" |
|||
> |
|||
<Modal.Header> |
|||
{isClearing |
|||
? t('clear.databases.modal.clearing.progress.title') |
|||
: t('clear.databases.modal.title')} |
|||
</Modal.Header> |
|||
<Modal.Content> |
|||
<Modal.Description> |
|||
{modalContent} |
|||
</Modal.Description> |
|||
</Modal.Content> |
|||
|
|||
{!isClearing && ( |
|||
<Modal.Actions> |
|||
<Button color="black" basic onClick={onCancelTry} disabled={isClearing}> |
|||
{t('clear.databases.modal.cancel.button')} |
|||
</Button> |
|||
<Button onClick={handleSubmit} negative disabled={!userConfirmed}> |
|||
{t('clear.databases.modal.clear.button')} |
|||
</Button> |
|||
</Modal.Actions> |
|||
)} |
|||
</Modal> |
|||
), [handleSubmit, isClearing, modalContent, onCancelTry, open, t, userConfirmed]); |
|||
}; |
|||
|
|||
ClearDatabasesModal.defaultProps = { |
|||
open: false, |
|||
}; |
|||
|
|||
ClearDatabasesModal.propTypes = { |
|||
open: PropTypes.bool, |
|||
onDatabasesCleared: PropTypes.func.isRequired, |
|||
onCancel: PropTypes.func.isRequired, |
|||
}; |
|||
|
|||
export default ClearDatabasesModal; |
@ -0,0 +1,22 @@ |
|||
import { breeze } from '../../redux/store'; |
|||
|
|||
const purgeIndexedDBs = async () => { |
|||
const { ipfs, orbit } = breeze; |
|||
|
|||
if (orbit) await orbit.stop(); |
|||
if (ipfs) await ipfs.stop(); |
|||
|
|||
const databases = await indexedDB.databases(); |
|||
return Promise.all( |
|||
databases.map((db) => new Promise( |
|||
(resolve, reject) => { |
|||
const request = indexedDB.deleteDatabase(db.name); |
|||
request.onblocked = resolve; |
|||
request.onsuccess = resolve; |
|||
request.onerror = reject; |
|||
}, |
|||
)), |
|||
); |
|||
}; |
|||
|
|||
export default purgeIndexedDBs; |
@ -0,0 +1,46 @@ |
|||
/* Patches browsers that do not yet support indexedDB.databases() |
|||
(https://developer.mozilla.org/en-US/docs/Web/API/IDBFactory/databases)
|
|||
See also https://gist.github.com/rmehner/b9a41d9f659c9b1c3340#gistcomment-3449418) */
|
|||
if (window.indexedDB && typeof window.indexedDB.databases === 'undefined') { |
|||
const LOCALSTORAGE_CACHE_KEY = 'indexedDBDatabases'; |
|||
|
|||
// Store a key value map of databases
|
|||
const getFromStorage = () => JSON.parse(window.localStorage[LOCALSTORAGE_CACHE_KEY] || '{}'); |
|||
|
|||
// Write the database to local storage
|
|||
const writeToStorage = (value) => { window.localStorage[LOCALSTORAGE_CACHE_KEY] = JSON.stringify(value); }; |
|||
|
|||
IDBFactory.prototype.databases = () => Promise.resolve( |
|||
Object.entries(getFromStorage()).reduce((acc, [name, version]) => { |
|||
acc.push({ name, version }); |
|||
return acc; |
|||
}, []), |
|||
); |
|||
|
|||
// Intercept the existing open handler to write our DBs names
|
|||
// and versions to localStorage
|
|||
const { open } = IDBFactory.prototype; |
|||
|
|||
// eslint-disable-next-line func-names
|
|||
IDBFactory.prototype.open = function (...args) { |
|||
const dbName = args[0]; |
|||
const version = args[1] || 1; |
|||
const existing = getFromStorage(); |
|||
writeToStorage({ ...existing, [dbName]: version }); |
|||
return open.apply(this, args); |
|||
}; |
|||
|
|||
// Intercept the existing deleteDatabase handler remove our
|
|||
// dbNames from localStorage
|
|||
const { deleteDatabase } = IDBFactory.prototype; |
|||
|
|||
// eslint-disable-next-line func-names
|
|||
IDBFactory.prototype.deleteDatabase = function (...args) { |
|||
const dbName = args[0]; |
|||
const existing = getFromStorage(); |
|||
delete existing[dbName]; |
|||
writeToStorage(existing); |
|||
return deleteDatabase.apply(this, args); |
|||
}; |
|||
console.debug('IndexedDB patched successfully!'); |
|||
} |
Loading…
Reference in new issue