refactor: Creating Medias reducer
This commit is contained in:
parent
9275aaec90
commit
1ba98fdb5a
@ -1,7 +1,7 @@
|
|||||||
import yaml from 'js-yaml';
|
import yaml from 'js-yaml';
|
||||||
import { currentBackend } from '../backends/backend';
|
import { currentBackend } from '../backends/backend';
|
||||||
import { authenticate } from '../actions/auth';
|
import { authenticate } from '../actions/auth';
|
||||||
import * as ImageProxy from '../valueObjects/ImageProxy';
|
import * as MediaProxy from '../valueObjects/MediaProxy';
|
||||||
|
|
||||||
export const CONFIG_REQUEST = 'CONFIG_REQUEST';
|
export const CONFIG_REQUEST = 'CONFIG_REQUEST';
|
||||||
export const CONFIG_SUCCESS = 'CONFIG_SUCCESS';
|
export const CONFIG_SUCCESS = 'CONFIG_SUCCESS';
|
||||||
@ -30,7 +30,7 @@ export function configFailed(err) {
|
|||||||
|
|
||||||
export function configDidLoad(config) {
|
export function configDidLoad(config) {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
ImageProxy.setConfig(config);
|
MediaProxy.setConfig(config);
|
||||||
dispatch(configLoaded(config));
|
dispatch(configLoaded(config));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -14,8 +14,7 @@ export const ENTRIES_FAILURE = 'ENTRIES_FAILURE';
|
|||||||
export const DRAFT_CREATE = 'DRAFT_CREATE';
|
export const DRAFT_CREATE = 'DRAFT_CREATE';
|
||||||
export const DRAFT_DISCARD = 'DRAFT_DISCARD';
|
export const DRAFT_DISCARD = 'DRAFT_DISCARD';
|
||||||
export const DRAFT_CHANGE = 'DRAFT_CHANGE';
|
export const DRAFT_CHANGE = 'DRAFT_CHANGE';
|
||||||
export const DRAFT_ADD_MEDIA = 'DRAFT_ADD_MEDIA';
|
|
||||||
export const DRAFT_REMOVE_MEDIA = 'DRAFT_REMOVE_MEDIA';
|
|
||||||
|
|
||||||
export const ENTRY_PERSIST_REQUEST = 'ENTRY_PERSIST_REQUEST';
|
export const ENTRY_PERSIST_REQUEST = 'ENTRY_PERSIST_REQUEST';
|
||||||
export const ENTRY_PERSIST_SUCCESS = 'ENTRY_PERSIST_SUCCESS';
|
export const ENTRY_PERSIST_SUCCESS = 'ENTRY_PERSIST_SUCCESS';
|
||||||
@ -125,20 +124,6 @@ export function changeDraft(entry) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addMediaToDraft(mediaFile) {
|
|
||||||
return {
|
|
||||||
type: DRAFT_ADD_MEDIA,
|
|
||||||
payload: mediaFile
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function removeMediaFromDraft(mediaFile) {
|
|
||||||
return {
|
|
||||||
type: DRAFT_REMOVE_MEDIA,
|
|
||||||
payload: mediaFile
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Exported Thunk Action Creators
|
* Exported Thunk Action Creators
|
||||||
*/
|
*/
|
||||||
|
5
src/actions/media.js
Normal file
5
src/actions/media.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export const ADD_MEDIA = 'ADD_MEDIA';
|
||||||
|
|
||||||
|
export function addMedia(file) {
|
||||||
|
return { type: ADD_MEDIA, payload: file };
|
||||||
|
}
|
@ -5,31 +5,6 @@ function getSlug(path) {
|
|||||||
return m && m[1];
|
return m && m[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFileData(file) {
|
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
const reader = new FileReader();
|
|
||||||
reader.onload = () => {
|
|
||||||
resolve(reader.result);
|
|
||||||
};
|
|
||||||
reader.onerror = function() {
|
|
||||||
reject('Unable to read file');
|
|
||||||
};
|
|
||||||
reader.readAsDataURL(file);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Only necessary in test-repo, where images won't actually be persisted on server
|
|
||||||
function changeFilePathstoBase64(mediaFolder, content, mediaFiles, base64Files) {
|
|
||||||
let _content = content;
|
|
||||||
|
|
||||||
mediaFiles.forEach((media, index) => {
|
|
||||||
const reg = new RegExp('\\b' + mediaFolder + '/' + media.name + '\\b', 'g');
|
|
||||||
_content = _content.replace(reg, base64Files[index]);
|
|
||||||
});
|
|
||||||
|
|
||||||
return _content;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class TestRepo {
|
export default class TestRepo {
|
||||||
constructor(config) {
|
constructor(config) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
@ -74,17 +49,9 @@ export default class TestRepo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
persist(collection, entry, mediaFiles = []) {
|
persist(collection, entry, mediaFiles = []) {
|
||||||
return new Promise((resolve, reject) => {
|
|
||||||
Promise.all(mediaFiles.map((file) => getFileData(file))).then(
|
|
||||||
(base64Files) => {
|
|
||||||
const content = changeFilePathstoBase64(this.config.get('media_folder'), entry.raw, mediaFiles, base64Files);
|
|
||||||
const folder = collection.get('folder');
|
const folder = collection.get('folder');
|
||||||
const fileName = entry.path.substring(entry.path.lastIndexOf('/') + 1);
|
const fileName = entry.path.substring(entry.path.lastIndexOf('/') + 1);
|
||||||
window.repoFiles[folder][fileName]['content'] = content;
|
window.repoFiles[folder][fileName]['content'] = entry.raw;
|
||||||
resolve({collection, entry});
|
return Promise.resolve({collection, entry});
|
||||||
},
|
|
||||||
(error) => reject({collection, entry, error})
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import Widgets from './Widgets';
|
|||||||
|
|
||||||
export default class ControlPane extends React.Component {
|
export default class ControlPane extends React.Component {
|
||||||
controlFor(field) {
|
controlFor(field) {
|
||||||
const { entry, onChange, onAddMedia, onRemoveMedia } = this.props;
|
const { entry, getMedia, onChange, onAddMedia } = this.props;
|
||||||
const widget = Widgets[field.get('widget')] || Widgets._unknown;
|
const widget = Widgets[field.get('widget')] || Widgets._unknown;
|
||||||
return React.createElement(widget.Control, {
|
return React.createElement(widget.Control, {
|
||||||
key: field.get('name'),
|
key: field.get('name'),
|
||||||
@ -11,7 +11,7 @@ export default class ControlPane extends React.Component {
|
|||||||
value: entry.getIn(['data', field.get('name')]),
|
value: entry.getIn(['data', field.get('name')]),
|
||||||
onChange: (value) => onChange(entry.setIn(['data', field.get('name')], value)),
|
onChange: (value) => onChange(entry.setIn(['data', field.get('name')], value)),
|
||||||
onAddMedia: onAddMedia,
|
onAddMedia: onAddMedia,
|
||||||
onRemoveMedia: onRemoveMedia
|
getMedia: getMedia
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ import PreviewPane from './PreviewPane';
|
|||||||
export default class EntryEditor extends React.Component {
|
export default class EntryEditor extends React.Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { collection, entry, onChange, onAddMedia, onRemoveMedia, onPersist } = this.props;
|
const { collection, entry, getMedia, onChange, onAddMedia, onPersist } = this.props;
|
||||||
return <div>
|
return <div>
|
||||||
<h1>Entry in {collection.get('label')}</h1>
|
<h1>Entry in {collection.get('label')}</h1>
|
||||||
<h2>{entry && entry.get('title')}</h2>
|
<h2>{entry && entry.get('title')}</h2>
|
||||||
@ -14,13 +14,13 @@ export default class EntryEditor extends React.Component {
|
|||||||
<ControlPane
|
<ControlPane
|
||||||
collection={collection}
|
collection={collection}
|
||||||
entry={entry}
|
entry={entry}
|
||||||
|
getMedia={getMedia}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
onAddMedia={onAddMedia}
|
onAddMedia={onAddMedia}
|
||||||
onRemoveMedia={onRemoveMedia}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="cms-preview-pane" style={styles.pane}>
|
<div className="cms-preview-pane" style={styles.pane}>
|
||||||
<PreviewPane collection={collection} entry={entry}/>
|
<PreviewPane collection={collection} entry={entry} getMedia={getMedia} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button onClick={onPersist}>Save</button>
|
<button onClick={onPersist}>Save</button>
|
||||||
|
@ -3,12 +3,13 @@ import Widgets from './Widgets';
|
|||||||
|
|
||||||
export default class PreviewPane extends React.Component {
|
export default class PreviewPane extends React.Component {
|
||||||
previewFor(field) {
|
previewFor(field) {
|
||||||
const { entry } = this.props;
|
const { entry, getMedia } = this.props;
|
||||||
const widget = Widgets[field.get('widget')] || Widgets._unknown;
|
const widget = Widgets[field.get('widget')] || Widgets._unknown;
|
||||||
return React.createElement(widget.Preview, {
|
return React.createElement(widget.Preview, {
|
||||||
key: field.get('name'),
|
key: field.get('name'),
|
||||||
field: field,
|
field: field,
|
||||||
value: entry.getIn(['data', field.get('name')])
|
value: entry.getIn(['data', field.get('name')]),
|
||||||
|
getMedia: getMedia,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { truncateMiddle } from '../../lib/textHelper';
|
import { truncateMiddle } from '../../lib/textHelper';
|
||||||
import ImageProxy from '../../valueObjects/ImageProxy';
|
|
||||||
|
|
||||||
const MAX_DISPLAY_LENGTH = 50;
|
const MAX_DISPLAY_LENGTH = 50;
|
||||||
|
|
||||||
@ -9,7 +8,7 @@ export default class ImageControl extends React.Component {
|
|||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
currentImage: props.value ? new ImageProxy(props.value, null, true) : null
|
currentImage: props.value
|
||||||
};
|
};
|
||||||
|
|
||||||
this.revokeCurrentImage = this.revokeCurrentImage.bind(this);
|
this.revokeCurrentImage = this.revokeCurrentImage.bind(this);
|
||||||
@ -22,8 +21,8 @@ export default class ImageControl extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
revokeCurrentImage() {
|
revokeCurrentImage() {
|
||||||
if (this.state.currentImage && !this.state.currentImage.uploaded) {
|
if (this.state.currentImage) {
|
||||||
this.props.onRemoveMedia(this.state.currentImage);
|
//this.props.onRemoveMedia(this.state.currentImage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,7 +48,6 @@ export default class ImageControl extends React.Component {
|
|||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
this.revokeCurrentImage();
|
this.revokeCurrentImage();
|
||||||
let imageRef = null;
|
|
||||||
const fileList = e.dataTransfer ? e.dataTransfer.files : e.target.files;
|
const fileList = e.dataTransfer ? e.dataTransfer.files : e.target.files;
|
||||||
const files = [...fileList];
|
const files = [...fileList];
|
||||||
const imageType = /^image\//;
|
const imageType = /^image\//;
|
||||||
@ -62,17 +60,20 @@ export default class ImageControl extends React.Component {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (file) {
|
if (file) {
|
||||||
imageRef = new ImageProxy(file.name, window.URL.createObjectURL(file, {oneTimeOnly: true}));
|
|
||||||
this.props.onAddMedia(file);
|
this.props.onAddMedia(file);
|
||||||
|
this.props.onChange(file.name);
|
||||||
|
this.setState({currentImage: file.name});
|
||||||
|
} else {
|
||||||
|
this.props.onChange(null);
|
||||||
|
this.setState({currentImage: null});
|
||||||
}
|
}
|
||||||
|
|
||||||
this.props.onChange(imageRef);
|
|
||||||
this.setState({currentImage: imageRef});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
renderImageName() {
|
renderImageName() {
|
||||||
|
|
||||||
if (!this.state.currentImage) return null;
|
if (!this.state.currentImage) return null;
|
||||||
return truncateMiddle(this.state.currentImage.uri, MAX_DISPLAY_LENGTH);
|
return truncateMiddle(this.props.getMedia(this.state.currentImage).uri, MAX_DISPLAY_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -6,7 +6,7 @@ export default class ImagePreview extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { value } = this.props;
|
const { value, getMedia } = this.props;
|
||||||
return value ? <img src={value}/> : null;
|
return value ? <img src={getMedia(value)}/> : null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import { Link } from 'react-router';
|
import { Link } from 'react-router';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { loadEntries } from '../actions/entries';
|
import { loadEntries } from '../actions/entries';
|
||||||
import { selectEntries } from '../reducers/entries';
|
import { selectEntries } from '../reducers';
|
||||||
import EntryListing from '../components/EntryListing';
|
import EntryListing from '../components/EntryListing';
|
||||||
|
|
||||||
class DashboardPage extends React.Component {
|
class DashboardPage extends React.Component {
|
||||||
|
@ -5,11 +5,10 @@ import {
|
|||||||
createDraft,
|
createDraft,
|
||||||
discardDraft,
|
discardDraft,
|
||||||
changeDraft,
|
changeDraft,
|
||||||
addMediaToDraft,
|
|
||||||
removeMediaFromDraft,
|
|
||||||
persist
|
persist
|
||||||
} from '../actions/entries';
|
} from '../actions/entries';
|
||||||
import { selectEntry } from '../reducers/entries';
|
import { addMedia } from '../actions/media';
|
||||||
|
import { selectEntry, getMedia } from '../reducers';
|
||||||
import EntryEditor from '../components/EntryEditor';
|
import EntryEditor from '../components/EntryEditor';
|
||||||
|
|
||||||
class EntryPage extends React.Component {
|
class EntryPage extends React.Component {
|
||||||
@ -40,17 +39,20 @@ class EntryPage extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { entry, entryDraft, collection, handleDraftChange, handleDraftAddMedia, handleDraftRemoveMedia } = this.props;
|
const {
|
||||||
|
entry, entryDraft, boundGetMedia, collection, handleDraftChange, handleAddMedia, handleDraftRemoveMedia
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
if (entry == null || entryDraft.get('entry') == undefined || entry.get('isFetching')) {
|
if (entry == null || entryDraft.get('entry') == undefined || entry.get('isFetching')) {
|
||||||
return <div>Loading...</div>;
|
return <div>Loading...</div>;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<EntryEditor
|
<EntryEditor
|
||||||
entry={entryDraft.get('entry')}
|
entry={entryDraft.get('entry')}
|
||||||
|
getMedia={boundGetMedia}
|
||||||
collection={collection}
|
collection={collection}
|
||||||
onChange={handleDraftChange}
|
onChange={handleDraftChange}
|
||||||
onAddMedia={handleDraftAddMedia}
|
onAddMedia={handleAddMedia}
|
||||||
onRemoveMedia={handleDraftRemoveMedia}
|
|
||||||
onPersist={this.handlePersist}
|
onPersist={this.handlePersist}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@ -62,15 +64,15 @@ function mapStateToProps(state, ownProps) {
|
|||||||
const collection = collections.get(ownProps.params.name);
|
const collection = collections.get(ownProps.params.name);
|
||||||
const slug = ownProps.params.slug;
|
const slug = ownProps.params.slug;
|
||||||
const entry = selectEntry(state, collection.get('name'), slug);
|
const entry = selectEntry(state, collection.get('name'), slug);
|
||||||
return {collection, collections, entryDraft, slug, entry};
|
const boundGetMedia = getMedia.bind(null, state);
|
||||||
|
return {collection, collections, entryDraft, boundGetMedia, slug, entry};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
mapStateToProps,
|
mapStateToProps,
|
||||||
{
|
{
|
||||||
handleDraftChange: changeDraft,
|
handleDraftChange: changeDraft,
|
||||||
handleDraftAddMedia: addMediaToDraft,
|
handleAddMedia: addMedia,
|
||||||
handleDraftRemoveMedia: removeMediaFromDraft,
|
|
||||||
loadEntry,
|
loadEntry,
|
||||||
createDraft,
|
createDraft,
|
||||||
discardDraft,
|
discardDraft,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import yaml from 'js-yaml';
|
import yaml from 'js-yaml';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import ImageProxy from '../valueObjects/ImageProxy';
|
import MediaProxy from '../valueObjects/MediaProxy';
|
||||||
|
|
||||||
const MomentType = new yaml.Type('date', {
|
const MomentType = new yaml.Type('date', {
|
||||||
kind: 'scalar',
|
kind: 'scalar',
|
||||||
@ -17,13 +17,13 @@ const MomentType = new yaml.Type('date', {
|
|||||||
|
|
||||||
const ImageType = new yaml.Type('image', {
|
const ImageType = new yaml.Type('image', {
|
||||||
kind: 'scalar',
|
kind: 'scalar',
|
||||||
instanceOf: ImageProxy,
|
instanceOf: MediaProxy,
|
||||||
represent: function(value) {
|
represent: function(value) {
|
||||||
return `${value.uri}`;
|
return `${value.uri}`;
|
||||||
},
|
},
|
||||||
resolve: function(value) {
|
resolve: function(value) {
|
||||||
if (value === null) return false;
|
if (value === null) return false;
|
||||||
if (value instanceof ImageProxy) return true;
|
if (value instanceof MediaProxy) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import Immutable from 'immutable';
|
import Immutable from 'immutable';
|
||||||
import { AUTH_REQUEST, AUTH_SUCCESS, AUTH_FAILURE } from '../actions/auth';
|
import { AUTH_REQUEST, AUTH_SUCCESS, AUTH_FAILURE } from '../actions/auth';
|
||||||
|
|
||||||
export function auth(state = null, action) {
|
const auth = (state = null, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case AUTH_REQUEST:
|
case AUTH_REQUEST:
|
||||||
return Immutable.Map({isFetching: true});
|
return Immutable.Map({isFetching: true});
|
||||||
@ -13,4 +13,6 @@ export function auth(state = null, action) {
|
|||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export default auth;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { OrderedMap, fromJS } from 'immutable';
|
import { OrderedMap, fromJS } from 'immutable';
|
||||||
import { CONFIG_SUCCESS } from '../actions/config';
|
import { CONFIG_SUCCESS } from '../actions/config';
|
||||||
|
|
||||||
export function collections(state = null, action) {
|
const collections = (state = null, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case CONFIG_SUCCESS:
|
case CONFIG_SUCCESS:
|
||||||
const collections = action.payload && action.payload.collections;
|
const collections = action.payload && action.payload.collections;
|
||||||
@ -14,3 +14,5 @@ export function collections(state = null, action) {
|
|||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default collections;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import Immutable from 'immutable';
|
import Immutable from 'immutable';
|
||||||
import { CONFIG_REQUEST, CONFIG_SUCCESS, CONFIG_FAILURE } from '../actions/config';
|
import { CONFIG_REQUEST, CONFIG_SUCCESS, CONFIG_FAILURE } from '../actions/config';
|
||||||
|
|
||||||
export function config(state = null, action) {
|
const config = (state = null, action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case CONFIG_REQUEST:
|
case CONFIG_REQUEST:
|
||||||
return Immutable.Map({isFetching: true});
|
return Immutable.Map({isFetching: true});
|
||||||
@ -12,4 +12,6 @@ export function config(state = null, action) {
|
|||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export default config;
|
||||||
|
@ -3,7 +3,7 @@ import {
|
|||||||
ENTRY_REQUEST, ENTRY_SUCCESS, ENTRIES_REQUEST, ENTRIES_SUCCESS
|
ENTRY_REQUEST, ENTRY_SUCCESS, ENTRIES_REQUEST, ENTRIES_SUCCESS
|
||||||
} from '../actions/entries';
|
} from '../actions/entries';
|
||||||
|
|
||||||
export function entries(state = Map({entities: Map(), pages: Map()}), action) {
|
const entries = (state = Map({entities: Map(), pages: Map()}), action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case ENTRY_REQUEST:
|
case ENTRY_REQUEST:
|
||||||
return state.setIn(['entities', `${action.payload.collection}.${action.payload.slug}`, 'isFetching'], true);
|
return state.setIn(['entities', `${action.payload.collection}.${action.payload.slug}`, 'isFetching'], true);
|
||||||
@ -28,13 +28,15 @@ export function entries(state = Map({entities: Map(), pages: Map()}), action) {
|
|||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
export function selectEntry(state, collection, slug) {
|
export const selectEntry = (state, collection, slug) => (
|
||||||
return state.entries.getIn(['entities', `${collection}.${slug}`]);
|
state.getIn(['entities', `${collection}.${slug}`])
|
||||||
}
|
);
|
||||||
|
|
||||||
export function selectEntries(state, collection) {
|
export const selectEntries = (state, collection) => {
|
||||||
const slugs = state.entries.getIn(['pages', collection, 'ids']);
|
const slugs = state.getIn(['pages', collection, 'ids']);
|
||||||
return slugs && slugs.map((slug) => selectEntry(state, collection, slug));
|
return slugs && slugs.map((slug) => selectEntry(state, collection, slug));
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export default entries;
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
import { Map, List } from 'immutable';
|
import { Map, List } from 'immutable';
|
||||||
import { DRAFT_CREATE, DRAFT_DISCARD, DRAFT_CHANGE, DRAFT_ADD_MEDIA, DRAFT_REMOVE_MEDIA } from '../actions/entries';
|
import { DRAFT_CREATE, DRAFT_DISCARD, DRAFT_CHANGE } from '../actions/entries';
|
||||||
|
import { ADD_MEDIA } from '../actions/media';
|
||||||
|
|
||||||
const initialState = Map({entry: Map(), mediaFiles: List()});
|
const initialState = Map({entry: Map(), mediaFiles: List()});
|
||||||
|
|
||||||
export function entryDraft(state = Map(), action) {
|
const entryDraft = (state = Map(), action) => {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case DRAFT_CREATE:
|
case DRAFT_CREATE:
|
||||||
if (!action.payload) {
|
if (!action.payload) {
|
||||||
@ -20,15 +21,12 @@ export function entryDraft(state = Map(), action) {
|
|||||||
case DRAFT_CHANGE:
|
case DRAFT_CHANGE:
|
||||||
return state.set('entry', action.payload);
|
return state.set('entry', action.payload);
|
||||||
|
|
||||||
case DRAFT_ADD_MEDIA:
|
case ADD_MEDIA:
|
||||||
return state.update('mediaFiles', (list) => list.push(action.payload));
|
return state.update('mediaFiles', (list) => list.push(action.payload.name));
|
||||||
|
|
||||||
case DRAFT_REMOVE_MEDIA:
|
|
||||||
const mediaIndex = state.get('mediaFiles').indexOf(action.payload);
|
|
||||||
if (mediaIndex === -1) return state;
|
|
||||||
return state.update('mediaFiles', (list) => list.splice(mediaIndex, 1));
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export default entryDraft;
|
||||||
|
27
src/reducers/index.js
Normal file
27
src/reducers/index.js
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import auth from './auth';
|
||||||
|
import config from './config';
|
||||||
|
import entries, * as fromEntries from './entries';
|
||||||
|
import entryDraft from './entryDraft';
|
||||||
|
import collections from './collections';
|
||||||
|
import medias, * as fromMedias from './medias';
|
||||||
|
|
||||||
|
const reducers = {
|
||||||
|
auth,
|
||||||
|
config,
|
||||||
|
collections,
|
||||||
|
entries,
|
||||||
|
entryDraft,
|
||||||
|
medias
|
||||||
|
};
|
||||||
|
|
||||||
|
export default reducers;
|
||||||
|
|
||||||
|
export const selectEntry = (state, collection, slug) =>
|
||||||
|
fromEntries.selectEntry(state.entries, collection, slug);
|
||||||
|
|
||||||
|
|
||||||
|
export const selectEntries = (state, collection) =>
|
||||||
|
fromEntries.selectEntries(state.entries, collection);
|
||||||
|
|
||||||
|
export const getMedia = (state, fileName) =>
|
||||||
|
fromMedias.getMedia(state.medias, fileName);
|
23
src/reducers/medias.js
Normal file
23
src/reducers/medias.js
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { Map } from 'immutable';
|
||||||
|
import { ADD_MEDIA } from '../actions/media';
|
||||||
|
import MediaProxy from '../valueObjects/MediaProxy';
|
||||||
|
|
||||||
|
const medias = (state = Map(), action) => {
|
||||||
|
switch (action.type) {
|
||||||
|
case ADD_MEDIA:
|
||||||
|
return state.set(action.payload.name, action.payload);
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export default medias;
|
||||||
|
|
||||||
|
export const getMedia = (state, filePath) => {
|
||||||
|
const fileName = filePath.substring(filePath.lastIndexOf('/') + 1);
|
||||||
|
if (state.has(fileName)) {
|
||||||
|
return new MediaProxy(fileName, window.URL.createObjectURL(state.get(fileName), {oneTimeOnly: true}));
|
||||||
|
} else {
|
||||||
|
return new MediaProxy(filePath, null, filePath, true);
|
||||||
|
}
|
||||||
|
};
|
@ -2,18 +2,10 @@ import { createStore, applyMiddleware, combineReducers, compose } from 'redux';
|
|||||||
import thunkMiddleware from 'redux-thunk';
|
import thunkMiddleware from 'redux-thunk';
|
||||||
import { browserHistory } from 'react-router';
|
import { browserHistory } from 'react-router';
|
||||||
import { syncHistory, routeReducer } from 'react-router-redux';
|
import { syncHistory, routeReducer } from 'react-router-redux';
|
||||||
import { auth } from '../reducers/auth';
|
import reducers from '../reducers';
|
||||||
import { config } from '../reducers/config';
|
|
||||||
import { entries } from '../reducers/entries';
|
|
||||||
import { entryDraft } from '../reducers/entryDraft';
|
|
||||||
import { collections } from '../reducers/collections';
|
|
||||||
|
|
||||||
const reducer = combineReducers({
|
const reducer = combineReducers({
|
||||||
auth,
|
...reducers,
|
||||||
config,
|
|
||||||
collections,
|
|
||||||
entries,
|
|
||||||
entryDraft,
|
|
||||||
router: routeReducer
|
router: routeReducer
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -3,10 +3,10 @@ export const setConfig = (configObj) => {
|
|||||||
config = configObj;
|
config = configObj;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function ImageProxy(value, objectURL, uploaded = false) {
|
export default function MediaProxy(value, objectURL, uri, uploaded = false) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
this.uploaded = uploaded;
|
this.uploaded = uploaded;
|
||||||
this.uri = config.media_folder && !uploaded ? config.media_folder + '/' + value : value;
|
this.uri = uri || config.media_folder && config.media_folder + '/' + value;
|
||||||
this.toString = function() {
|
this.toString = function() {
|
||||||
return uploaded ? this.uri : objectURL;
|
return uploaded ? this.uri : objectURL;
|
||||||
};
|
};
|
Loading…
x
Reference in New Issue
Block a user