UNPKG

ra-data-firebase

Version:

Firebase data provider for React Admin

184 lines (157 loc) 5.05 kB
import firebase from 'firebase' import sortBy from 'sort-by' import { CREATE } from 'react-admin' const getImageSize = (file) => { return new Promise(resolve => { const img = document.createElement('img') img.onload = function () { resolve({ width: this.width, height: this.height }) } img.src = file.src }) } const upload = async (fieldName, submitedData, id, resourceName, resourcePath) => { let file = submitedData[fieldName] && Array.isArray(submitedData[fieldName]) ? submitedData[fieldName][0] : submitedData[fieldName] const result = {} if (file && file.rawFile && file.rawFile.name) { const rawFile = file.rawFile const ref = firebase.storage().ref().child(`${resourcePath}/${id}/${fieldName}`) const snapshot = await ref.put(rawFile) result[fieldName] = [{}] result[fieldName][0].uploadedAt = Date.now() result[fieldName][0].src = snapshot.downloadURL.split('?').shift() + '?alt=media' result[fieldName][0].type = rawFile.type if (rawFile.type.indexOf('image/') === 0) { try { const imageSize = await getImageSize(file) result[fieldName][0].width = imageSize.width result[fieldName][0].height = imageSize.height } catch (e) { console.error(`Failed to get image dimensions`) } } return result } return false } const save = async (id, data, previous, resourceName, resourcePath, firebaseSaveFilter, uploadResults, isNew, metaFieldNames) => { const currentUser = firebase.auth().currentUser if (uploadResults) { uploadResults.map(uploadResult => uploadResult ? Object.assign(data, uploadResult) : false) } if (isNew) { Object.assign(data, { [metaFieldNames.createdAt]: Date.now() }) } if (currentUser) { Object.assign(data, { [metaFieldNames.createdBy]: currentUser.uid }) } data = Object.assign(previous, { [metaFieldNames.updatedAt]: Date.now() }, data) if (!data.key) { data.key = id } if (!data.id) { data.id = id } await firebase.database().ref(`${resourcePath}/${data.key}`).update(firebaseSaveFilter(data)) return { data } } const del = async (id, resourceName, resourcePath, uploadFields) => { if (uploadFields.length) { uploadFields.map(fieldName => firebase.storage().ref().child(`${resourcePath}/${id}/${fieldName}`).delete()) } await firebase.database().ref(`${resourcePath}/${id}`).remove() return { data: id } } const getItemID = (params, type, resourceName, resourcePath, resourceData) => { let itemId = params.data.id || params.id || params.data.key || params.key if (!itemId) { itemId = firebase.database().ref().child(resourcePath).push().key } if (!itemId) { throw new Error('ID is required') } if (resourceData && resourceData[itemId] && type === CREATE) { throw new Error('ID already in use') } return itemId } const getOne = (params, resourceName, resourceData) => { if (params.id && resourceData[params.id]) { return { data: resourceData[params.id] } } else { throw new Error('Key not found') } } const getMany = (params, resourceName, resourceData) => { let ids = [] let data = [] let total = 0 if (params.ids && Array.isArray(params.ids)) { /** GET_MANY */ params.ids.forEach(key => { if (resourceData[key]) { ids.push(key) data.push(resourceData[key]) total++ } }) return {total, ids, data} } else if (params.pagination) { /** GET_LIST / GET_MANY_REFERENCE */ let values = [] // Copy the filter params so we can modify for GET_MANY_REFERENCE support. const filter = Object.assign({}, params.filter) if (params.target && params.id) { filter[params.target] = params.id } const filterKeys = Object.keys(filter) /* TODO Must have a better way */ if (filterKeys.length) { Object.values(resourceData).map(value => { let filterIndex = 0 while (filterIndex < filterKeys.length) { let property = filterKeys[filterIndex] if (property !== 'q' && value[property] !== filter[property]) { return filterIndex } else if (property === 'q') { if (JSON.stringify(value).indexOf(filter['q']) === -1) { return filterIndex } } filterIndex++ } values.push(value) return filterIndex }) } else { values = Object.values(resourceData) } if (params.sort) { values.sort(sortBy(`${params.sort.order === 'ASC' ? '-' : ''}${params.sort.field}`)) } const keys = values.map(i => i.id) const { page, perPage } = params.pagination const _start = (page - 1) * perPage const _end = page * perPage data = values.slice(_start, _end) ids = keys.slice(_start, _end) total = values.length return { data, ids, total } } else { throw new Error('Error processing request') } } export default { upload, save, del, getItemID, getOne, getMany }