<commit_before>/*
 * owo-whats this - Core file
 *
 * Contributed by:
 * | Capuccino
 * | Ovyerus
 *
 * Licensed under MIT. Copyright (c) 2017 Capuccino, Ovyerus and the repository contributors.
 */

// Framework imports
const Eris = require('eris');
const fs = require('fs');

//globals w

global.__baseDir = __dirname;
global.Promise = require('bluebird');
global.logger = require(`${__dirname}/lib/logger`);

// Custom modules
const logger = require(`${__dirname}/lib/logger`);
const CommandHolder = require(`${__dirname}/lib/commands`);
const utils = require(`${__dirname}/lib/utils`);

// Setup stuff
const config = require(`${__dirname}/config.json`);
const bot = new Eris(config.token, {
    autoreconnect: true,
    seedVoiceConnections: true,
    maxShards: config.maxShards || 1,
    disableEvents: {
        TYPING_START: true
    }
});
var loadCommands = true;
var allowCommandUse = false;

// Create data files
try {
    require.resolve(`${__dirname}/data/data.json`);
} catch (err) {
    fs.mkdirSync(`${__dirname}/data/`);
    fs.writeFile(`${__dirname}/data/data.json`, JSON.stringify({ admins: [], blacklist: [] }), e => {
        if (e) {
            throw e;
        } else {
            logger.info('Created data.json.');
        }
    });
}

try {
    require.resolve(`${__dirname}/data/prefixes.json`);
} catch (err) {
    fs.writeFile(`${__dirname}/data/prefixes.json`, JSON.stringify([]), e => {
        if (e) {
            throw e;
        } else {
            logger.info('Created prefixes.json.');
        }
    });
}

exports.bot = bot;

bot.logger = logger;
bot.commands = new CommandHolder();
bot.config = config;
bot.music = {
    skips: new Eris.Collection(Object),
    queues: new Eris.Collection(Object),
    channels: new Eris.Collection(Eris.Channel),
    guilds: new Eris.Collection(Eris.Guild),
    connections: new Eris.Collection(Eris.VoiceConnection),
    streams: new Eris.Collection(Object),
    stopped: []
};

// Init
bot.on('ready', () => {
    if (loadCommands) {
        require(`${__dirname}/lib/commandLoader.js`).init().then(() => {
            var altPrefixes = JSON.parse(fs.readFileSync(`${__dirname}/data/prefixes.json`));
            logger.info(`Loaded ${bot.commands.length} ${bot.commands.length === 1 ? 'command' : 'commands'}.`);
            logger.info(`${bot.user.username} is connected to Discord and ready to use.`);
            logger.info(`Main prefix is '${config.mainPrefix}', can also use @mention.`);
            logger.info(`${altPrefixes.length > 0 ? `Alternative prefixes: '${altPrefixes.join("', ")}'` : 'No alternative prefixes.'}`);
            loadCommands = false;
            allowCommandUse = true;
        }).catch(err => {
            console.error(`Experienced error while loading commands:\n${config.debug ? err.stack : err}`);
        });
    } else {
        logger.info('Reconnected to Discord from disconnect.');
    }

    bot.editStatus('online', {name: `${config.gameName || `${config.prefix}help for commands!`} | ${bot.guilds.size} ${bot.guilds.size === 1 ? 'server' : 'servers'}`, type: config.gameURL ? 1 : 0, url: `${config.gameURL || null}`});
});

bot.on('shardReady', shard => {
    logger.custom('blue', 'shard/shardInfo', `shard ${shard} is ready!`);
});

bot.on('shardResume', shard => {
    logger.custom('blue', 'shard/shardInfo', `shard ${shard} has resumed.`);
});

bot.on('guildCreate', g => {
    if (g.members.filter(m => m.bot).length >= Math.ceil(g.memberCount / 2)) {
        logger.info(`Detected bot collection guild. Autoleaving.... (${g.name} [${g.id}])`);
        g.leave();
    } else {
        bot.editStatus('online', {name: `${config.gameName || `${config.prefix}help for commands!`} | ${bot.guilds.size} ${bot.guilds.size === 1 ? 'server' : 'servers'}`, type: config.gameURL ? 1 : 0, url: `${config.gameURL || null}`});
    }
});

bot.on('guildDelete', () => {
    bot.editStatus('online', {name: `${config.gameName || `${config.prefix}help for commands!`} | ${bot.guilds.size} ${bot.guilds.size === 1 ? 'server' : 'servers'}`, type: config.gameURL ? 1 : 0, url: `${config.gameURL || null}`});
});

const prefixParser = require(`${__dirname}/lib/prefixParser.js`);

// Command handler
bot.on('messageCreate', msg => {
    if (!allowCommandUse || msg.author.id === bot.user.id || msg.author.bot || utils.isBlacklisted(msg.author.id)) return;
    if (!msg.channel.guild) {
        logger.custom('cyan', 'dm', loggerPrefix(msg) + msg.cleanContent);
        return;
    }

    prefixParser(msg.content).then(content => {
        if (content === undefined) return;

        var args = content.split(' ');
        var cmd = args.shift();
        var suffix = args.join(' ');
        var cleanSuffix = msg.cleanContent.split(' ');
        cleanSuffix.splice(0, 1);
        cleanSuffix = cleanSuffix.join(' ');
        var guildBot = msg.channel.guild.members.get(bot.user.id);

        var ctx = {msg, args, cmd, suffix, cleanSuffix, guildBot};

        if (bot.commands.getCommand(cmd)) {
            logger.cmd(loggerPrefix(msg) + msg.cleanContent);

            if (bot.commands.getCommand(cmd).adminOnly && (utils.isOwner(msg.author.id) || utils.isAdmin(msg.author.id))) {
                bot.commands.runCommand(cmd, bot, ctx).then(() => {
                    logger.cmd(loggerPrefix(msg) + `Successfully ran owner command '${cmd}'`);
                }).catch(err => {
                    handleCmdErr(msg, cmd, err);
                });
            } else if (bot.commands.getCommand(cmd).adminOnly) {
                msg.channel.createMessage(`Hey ${msg.author.mention}, you do not have permission to do that! :<`);
            } else {
                bot.commands.runCommand(cmd, bot, ctx).then(() => {
                    logger.cmd(loggerPrefix(msg) + `Successfully ran command '${cmd}'`);
                }).catch(err => {
                    handleCmdErr(msg, cmd, err);
                });
            }
        }
    }).catch(err => {
        logger.customError('prefixParser', `Failed to parse message for prefix: ${err}${config.debug ? `\n${err.stack}` : ''}`);
    });
});

// Handle disconnect
bot.on('disconnect', () => {
    logger.warn('Disconnected from Discord.');
});
bot.on('shardDisconnect', (err, shard) => {
    if (err) logger.customError('shard/shardStatus', `Shard ${shard} disconnected. Reason ${err}`);
});

// Music Shit
bot.on('voiceChannelLeave', (mem, chan) => {
    if (chan.voiceMembers.filter(m => m.id !== bot.user.id && !m.bot).length === 0 && chan.voiceMembers.get(bot.user.id)) {
        setTimeout(() => {
            let c = bot.guilds.get(chan.guild.id).channels.get(chan.id);
            if (c.voiceMembers.filter(m => m.id !== bot.user.id && !m.bot).length === 0) {
                if (bot.music.connections.get(chan.guild.id).playing) bot.music.connetions.get(chan.guild.id).stopPlaying();
                bot.music.connections.get(chan.guild.id).leave();
            }
        }, 60000);
    }

    if (mem.id !== bot.user.id) return;
    if (bot.music.channels.get(chan.id)) bot.music.channels.delete(chan.id);
    if (bot.music.guilds.get(chan.guild.id)) bot.music.guilds.delete(chan.guild.id);
    if (bot.music.connections.get(chan.guild.id)) bot.music.connections.delete(chan.guild.id);
    if (bot.music.queues.get(chan.guild.id)) bot.music.queues.delete(chan.guild.id);
    if (bot.music.skips.get(chan.guild.id)) bot.music.skips.delete(chan.guild.id);
    if (bot.music.streams.get(chan.guild.id)) {
        bot.music.streams.get(chan.guild.id).stream.destroy();
        bot.music.streams.delete(chan.guild.id);
    }
});

bot.on('voiceChannelSwitch', (mem, chan, old) => {
    if (mem.id !== bot.user.id) return;
    if (bot.music.channels.get(old.id)) {
        bot.music.channels.delete(old.id);
        bot.music.channels.add(chan);
    } else {
        bot.music.channels.add(chan);
    }
});

bot.connect();

// Functions
function loggerPrefix(msg) {
    return msg.channel.guild ? `${msg.channel.guild.name} | ${msg.channel.name} > ${utils.formatUsername(msg.author)} (${msg.author.id}): ` : `Direct Message > ${utils.formatUsername(msg.author)} (${msg.author.id}): `;
}

function handleCmdErr(msg, cmd, err) {
    if (err.response) var resp = JSON.parse(err.response);
    if (resp && resp.code === 50013) {
        logger.warn(`Can't send message in '#${msg.channel.name}' (${msg.channel.id}), cmd from user '${utils.formatUsername(msg.author)}' (${msg.author.id})`);
        msg.author.getDMChannel().then(dm => {
            console.log(dm.id);
            return dm.createMessage(`It appears I was unable to send a message in \`#${msg.channel.name}\` on the server \`${msg.channel.guild.name}\`. Please give me the Send Messages permission or notify a mod or admin if you cannot do this.`);
        }).catch(() => logger.warn(`Couldn't get DM channel for/send DM to ${utils.formatUsername(msg.author)} (${msg.author.id})`));
    } else if (resp && /\{'code':.+, 'message':.+\}/.test(err.response) && resp.code !== 50013) {
        logger.warn(loggerPrefix(msg) + `Discord error running command "${cmd}":\n:${config.debug ? err.stack : err}`);
        let m = `Discord error while trying to execute \`${cmd}\`\n`;
        m += '```js\n';
        m += `Code: ${resp.code}. Message: ${resp.message}\n`;
        m += "``` If you feel this shouldn't be happening, join my support server. Invite can be found in the `invite` command.";
        msg.channel.createMessage(m);
    } else {
        logger.error(loggerPrefix(msg) + `Error running command "${cmd}":\n${config.debug ? err.stack : err}`);
        let m = `Experienced error while executing \`${cmd}\`\n`;
        m += '```js\n';
        m += err + '\n';
        m += "``` If you feel this shouldn't be happening, join my support server. Invite can be found in the `invite` command.";
        msg.channel.createMessage(m);
    }
}

bot.awaitMessage = (channelID, userID, filter = function () { return true; }, timeout = 15000) => {
    return new Promise((resolve, reject) => {
        if (!channelID || typeof channelID !== 'string') {
            reject(new Error(`Unwanted type of channelID: got "${typeof channelID}" expected "string"`));
        } else if (!userID || typeof userID !== 'string') {
            reject(new Error(`Unwanted type of userID: got "${typeof userID}" expected "string"`));
        } else {
            var responded, rmvTimeout;

            var onCrt = (msg) => {
                if (msg.channel.id === channelID && msg.author.id === userID && filter(msg)) {
                    responded = true;
                    return msg;
                }
            };

            var onCrtWrap = (msg) => {
                var res = onCrt(msg);
                if (responded) {
                    bot.removeListener('messageCreate', onCrtWrap);
                    clearInterval(rmvTimeout);
                    resolve(res);
                }
            };

            bot.on('messageCreate', onCrtWrap);

            rmvTimeout = setTimeout(() => {
                if (!responded) {
                    bot.removeListener('messageCreate', onCrtWrap);
                    reject(new Error('Message await expired.'));
                }
            }, timeout);
        }
    });
};<commit_msg>redo gameName<commit_after>/*
 * owo-whats this - Core file
 *
 * Contributed by:
 * | Capuccino
 * | Ovyerus
 *
 * Licensed under MIT. Copyright (c) 2017 Capuccino, Ovyerus and the repository contributors.
 */

// Framework imports
const Eris = require('eris');
const fs = require('fs');

//globals w

global.__baseDir = __dirname;
global.Promise = require('bluebird');
global.logger = require(`${__dirname}/lib/logger`);

// Custom modules
const logger = require(`${__dirname}/lib/logger`);
const CommandHolder = require(`${__dirname}/lib/commands`);
const utils = require(`${__dirname}/lib/utils`);

// Setup stuff
const config = require(`${__dirname}/config.json`);
const bot = new Eris(config.token, {
    autoreconnect: true,
    seedVoiceConnections: true,
    maxShards: config.maxShards || 1,
    disableEvents: {
        TYPING_START: true
    }
});
var loadCommands = true;
var allowCommandUse = false;

// Create data files
try {
    require.resolve(`${__dirname}/data/data.json`);
} catch (err) {
    fs.mkdirSync(`${__dirname}/data/`);
    fs.writeFile(`${__dirname}/data/data.json`, JSON.stringify({ admins: [], blacklist: [] }), e => {
        if (e) {
            throw e;
        } else {
            logger.info('Created data.json.');
        }
    });
}

try {
    require.resolve(`${__dirname}/data/prefixes.json`);
} catch (err) {
    fs.writeFile(`${__dirname}/data/prefixes.json`, JSON.stringify([]), e => {
        if (e) {
            throw e;
        } else {
            logger.info('Created prefixes.json.');
        }
    });
}

exports.bot = bot;

bot.logger = logger;
bot.commands = new CommandHolder();
bot.config = config;
bot.music = {
    skips: new Eris.Collection(Object),
    queues: new Eris.Collection(Object),
    channels: new Eris.Collection(Eris.Channel),
    guilds: new Eris.Collection(Eris.Guild),
    connections: new Eris.Collection(Eris.VoiceConnection),
    streams: new Eris.Collection(Object),
    stopped: []
};

// Init
bot.on('ready', () => {
    if (loadCommands) {
        require(`${__dirname}/lib/commandLoader.js`).init().then(() => {
            var altPrefixes = JSON.parse(fs.readFileSync(`${__dirname}/data/prefixes.json`));
            logger.info(`Loaded ${bot.commands.length} ${bot.commands.length === 1 ? 'command' : 'commands'}.`);
            logger.info(`${bot.user.username} is connected to Discord and ready to use.`);
            logger.info(`Main prefix is '${config.mainPrefix}', can also use @mention.`);
            logger.info(`${altPrefixes.length > 0 ? `Alternative prefixes: '${altPrefixes.join("', ")}'` : 'No alternative prefixes.'}`);
            loadCommands = false;
            allowCommandUse = true;
        }).catch(err => {
            console.error(`Experienced error while loading commands:\n${config.debug ? err.stack : err}`);
        });
    } else {
        logger.info('Reconnected to Discord from disconnect.');
    }

    bot.editStatus('online', {name: `${config.gameName || `${config.mainPrefix}help for commands!`} | ${bot.guilds.size} ${bot.guilds.size === 1 ? 'server' : 'servers'}`, type: config.gameURL ? 1 : 0, url: `${config.gameURL || null}`});
});

bot.on('shardReady', shard => {
    logger.custom('blue', 'shard/shardInfo', `shard ${shard} is ready!`);
});

bot.on('shardResume', shard => {
    logger.custom('blue', 'shard/shardInfo', `shard ${shard} has resumed.`);
});

bot.on('guildCreate', g => {
    if (g.members.filter(m => m.bot).length >= Math.ceil(g.memberCount / 2)) {
        logger.info(`Detected bot collection guild. Autoleaving.... (${g.name} [${g.id}])`);
        g.leave();
    } else {
        bot.editStatus('online', {name: `${config.gameName || `${config.mainPrefix}help for commands!`} | ${bot.guilds.size} ${bot.guilds.size === 1 ? 'server' : 'servers'}`, type: config.gameURL ? 1 : 0, url: `${config.gameURL || null}`});
    }
});

bot.on('guildDelete', () => {
    bot.editStatus('online', {name: `${config.gameName || `${config.mainPrefix}help for commands!`} | ${bot.guilds.size} ${bot.guilds.size === 1 ? 'server' : 'servers'}`, type: config.gameURL ? 1 : 0, url: `${config.gameURL || null}`});
});

const prefixParser = require(`${__dirname}/lib/prefixParser.js`);

// Command handler
bot.on('messageCreate', msg => {
    if (!allowCommandUse || msg.author.id === bot.user.id || msg.author.bot || utils.isBlacklisted(msg.author.id)) return;
    if (!msg.channel.guild) {
        logger.custom('cyan', 'dm', loggerPrefix(msg) + msg.cleanContent);
        return;
    }

    prefixParser(msg.content).then(content => {
        if (content === undefined) return;

        var args = content.split(' ');
        var cmd = args.shift();
        var suffix = args.join(' ');
        var cleanSuffix = msg.cleanContent.split(' ');
        cleanSuffix.splice(0, 1);
        cleanSuffix = cleanSuffix.join(' ');
        var guildBot = msg.channel.guild.members.get(bot.user.id);

        var ctx = {msg, args, cmd, suffix, cleanSuffix, guildBot};

        if (bot.commands.getCommand(cmd)) {
            logger.cmd(loggerPrefix(msg) + msg.cleanContent);

            if (bot.commands.getCommand(cmd).adminOnly && (utils.isOwner(msg.author.id) || utils.isAdmin(msg.author.id))) {
                bot.commands.runCommand(cmd, bot, ctx).then(() => {
                    logger.cmd(loggerPrefix(msg) + `Successfully ran owner command '${cmd}'`);
                }).catch(err => {
                    handleCmdErr(msg, cmd, err);
                });
            } else if (bot.commands.getCommand(cmd).adminOnly) {
                msg.channel.createMessage(`Hey ${msg.author.mention}, you do not have permission to do that! :<`);
            } else {
                bot.commands.runCommand(cmd, bot, ctx).then(() => {
                    logger.cmd(loggerPrefix(msg) + `Successfully ran command '${cmd}'`);
                }).catch(err => {
                    handleCmdErr(msg, cmd, err);
                });
            }
        }
    }).catch(err => {
        logger.customError('prefixParser', `Failed to parse message for prefix: ${err}${config.debug ? `\n${err.stack}` : ''}`);
    });
});

// Handle disconnect
bot.on('disconnect', () => {
    logger.warn('Disconnected from Discord.');
});
bot.on('shardDisconnect', (err, shard) => {
    if (err) logger.customError('shard/shardStatus', `Shard ${shard} disconnected. Reason ${err}`);
});

// Music Shit
bot.on('voiceChannelLeave', (mem, chan) => {
    if (chan.voiceMembers.filter(m => m.id !== bot.user.id && !m.bot).length === 0 && chan.voiceMembers.get(bot.user.id)) {
        setTimeout(() => {
            let c = bot.guilds.get(chan.guild.id).channels.get(chan.id);
            if (c.voiceMembers.filter(m => m.id !== bot.user.id && !m.bot).length === 0) {
                if (bot.music.connections.get(chan.guild.id).playing) bot.music.connetions.get(chan.guild.id).stopPlaying();
                bot.music.connections.get(chan.guild.id).leave();
            }
        }, 60000);
    }

    if (mem.id !== bot.user.id) return;
    if (bot.music.channels.get(chan.id)) bot.music.channels.delete(chan.id);
    if (bot.music.guilds.get(chan.guild.id)) bot.music.guilds.delete(chan.guild.id);
    if (bot.music.connections.get(chan.guild.id)) bot.music.connections.delete(chan.guild.id);
    if (bot.music.queues.get(chan.guild.id)) bot.music.queues.delete(chan.guild.id);
    if (bot.music.skips.get(chan.guild.id)) bot.music.skips.delete(chan.guild.id);
    if (bot.music.streams.get(chan.guild.id)) {
        bot.music.streams.get(chan.guild.id).stream.destroy();
        bot.music.streams.delete(chan.guild.id);
    }
});

bot.on('voiceChannelSwitch', (mem, chan, old) => {
    if (mem.id !== bot.user.id) return;
    if (bot.music.channels.get(old.id)) {
        bot.music.channels.delete(old.id);
        bot.music.channels.add(chan);
    } else {
        bot.music.channels.add(chan);
    }
});

bot.connect();

// Functions
function loggerPrefix(msg) {
    return msg.channel.guild ? `${msg.channel.guild.name} | ${msg.channel.name} > ${utils.formatUsername(msg.author)} (${msg.author.id}): ` : `Direct Message > ${utils.formatUsername(msg.author)} (${msg.author.id}): `;
}

function handleCmdErr(msg, cmd, err) {
    if (err.response) var resp = JSON.parse(err.response);
    if (resp && resp.code === 50013) {
        logger.warn(`Can't send message in '#${msg.channel.name}' (${msg.channel.id}), cmd from user '${utils.formatUsername(msg.author)}' (${msg.author.id})`);
        msg.author.getDMChannel().then(dm => {
            console.log(dm.id);
            return dm.createMessage(`It appears I was unable to send a message in \`#${msg.channel.name}\` on the server \`${msg.channel.guild.name}\`. Please give me the Send Messages permission or notify a mod or admin if you cannot do this.`);
        }).catch(() => logger.warn(`Couldn't get DM channel for/send DM to ${utils.formatUsername(msg.author)} (${msg.author.id})`));
    } else if (resp && /\{'code':.+, 'message':.+\}/.test(err.response) && resp.code !== 50013) {
        logger.warn(loggerPrefix(msg) + `Discord error running command "${cmd}":\n:${config.debug ? err.stack : err}`);
        let m = `Discord error while trying to execute \`${cmd}\`\n`;
        m += '```js\n';
        m += `Code: ${resp.code}. Message: ${resp.message}\n`;
        m += "``` If you feel this shouldn't be happening, join my support server. Invite can be found in the `invite` command.";
        msg.channel.createMessage(m);
    } else {
        logger.error(loggerPrefix(msg) + `Error running command "${cmd}":\n${config.debug ? err.stack : err}`);
        let m = `Experienced error while executing \`${cmd}\`\n`;
        m += '```js\n';
        m += err + '\n';
        m += "``` If you feel this shouldn't be happening, join my support server. Invite can be found in the `invite` command.";
        msg.channel.createMessage(m);
    }
}

bot.awaitMessage = (channelID, userID, filter = function () { return true; }, timeout = 15000) => {
    return new Promise((resolve, reject) => {
        if (!channelID || typeof channelID !== 'string') {
            reject(new Error(`Unwanted type of channelID: got "${typeof channelID}" expected "string"`));
        } else if (!userID || typeof userID !== 'string') {
            reject(new Error(`Unwanted type of userID: got "${typeof userID}" expected "string"`));
        } else {
            var responded, rmvTimeout;

            var onCrt = (msg) => {
                if (msg.channel.id === channelID && msg.author.id === userID && filter(msg)) {
                    responded = true;
                    return msg;
                }
            };

            var onCrtWrap = (msg) => {
                var res = onCrt(msg);
                if (responded) {
                    bot.removeListener('messageCreate', onCrtWrap);
                    clearInterval(rmvTimeout);
                    resolve(res);
                }
            };

            bot.on('messageCreate', onCrtWrap);

            rmvTimeout = setTimeout(() => {
                if (!responded) {
                    bot.removeListener('messageCreate', onCrtWrap);
                    reject(new Error('Message await expired.'));
                }
            }, timeout);
        }
    });
};<|endoftext|>


<commit_before>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

import { newSortDataBy } from '../../../utilities';

/**
 * Immutably clears the current focus
 * @param {object} currState  the copy of state you want affected
 * @return {object}           New state with no cell focused
 */
const clearFocus = state => {
  const { dataState, currentFocusedRowKey } = state;
  if (!currentFocusedRowKey) {
    return state;
  }

  const newDataState = new Map(dataState);
  const currentRowState = newDataState.get(currentFocusedRowKey);
  newDataState.set(currentFocusedRowKey, {
    ...currentRowState,
    focusedColumn: null,
  });

  return { ...state, dataState: newDataState, currentFocusedRowKey: null };
};

/**
 * Immutably sets the current focus to the cell identified by `rowKey` and `columnKey`
 * @param {object} state  The copy of state to affect
 * @param {string} rowKey     The key of the row the cell to focus is in
 * @param {string} columnKey  The key of the column the cell to focus is in
 * @return {object}           A new object with a cell focused
 */
const setFocus = (state, rowKey, columnKey) => {
  const { dataState, currentFocusedRowKey } = state;
  const newDataState = new Map(dataState);

  // Clear previous focus if in a different row
  if (currentFocusedRowKey && rowKey !== currentFocusedRowKey) {
    const currentRowState = newDataState.get(currentFocusedRowKey);
    newDataState.set(currentFocusedRowKey, {
      ...currentRowState,
      focusedColumn: null,
    });
  }

  // Update focusedColumn in specified row
  const nextRowState = newDataState.get(rowKey);
  newDataState.set(rowKey, {
    ...nextRowState,
    focusedColumn: columnKey,
  });

  return {
    ...state,
    dataState: newDataState,
    currentFocusedRowKey: rowKey,
  };
};

/**
 *
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 */
export const filterData = (state, action) => {
  const { backingData, filterDataKeys, sortBy, isAscending } = state;
  const { searchTerm } = action;

  const queryString = filterDataKeys
    .map(filterTerm => `${filterTerm} CONTAINS[c]  $0`)
    .join(' OR ');

  const filteredData = backingData.filtered(queryString, searchTerm).slice();

  return {
    ...state,
    data: sortBy ? newSortDataBy(filteredData, sortBy, isAscending) : filteredData,
  };
};

export const editTotalQuantity = (state, action) => {
  const { rowKey } = action;
  const { dataState } = state;

  // Change object reference of row in `dataState` to trigger rerender of that row.
  // Realm object reference in `data` can't be affected in any tidy manner.
  const newDataState = new Map(dataState);
  const nextRowState = newDataState.get(rowKey);
  newDataState.set(rowKey, { ...nextRowState });

  return { ...state, dataState: newDataState };
};

/**
 * Focus the next appropriate cell after the current cell provided in action
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 */
export const focusNextCell = (state, action) => {
  const { data, columns, keyExtractor } = state;
  const { rowKey, columnKey } = action;

  // Handle finding next cell to focus
  let nextEditableColKey;
  const currentColIndex = columns.findIndex(col => col.key === columnKey);
  for (let index = currentColIndex + 1; index < columns.length; index++) {
    if (columns[index].type === 'editable') {
      nextEditableColKey = columns[index].key;
      break;
    }
  }

  if (nextEditableColKey) {
    // Focus next editable cell in row
    return setFocus(state, rowKey, nextEditableColKey);
  }

  // Attempt moving focus to next row
  const nextRowIndex = data.findIndex(row => keyExtractor(row) === rowKey) + 1;

  if (nextRowIndex < data.length) {
    // Focus first editable cell in next row
    const nextRowKey = keyExtractor(data[nextRowIndex]);
    const firstEditableColKey = columns.find(col => col.type === 'editable').key;
    return setFocus(state, nextRowKey, firstEditableColKey);
  }

  // We were on the last row and last column, so unfocus current cell
  return clearFocus(state);
};

/**
 * Sets the provided row in action as selected
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 * Action: { type: 'selectRow', rowKey }
 */
export const selectRow = (state, action) => {
  const { dataState } = state;
  const { rowKey } = action;
  const newDataState = new Map(dataState);

  const rowState = newDataState.get(rowKey);
  newDataState.set(rowKey, {
    ...rowState,
    isSelected: true,
  });

  return { ...state, dataState: newDataState, hasSelection: true };
};

/**
 * Removes the provided row in action from being
 * selected.
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 * Action: { type: 'deselectRow', rowKey }
 */
export const deselectRow = (state, action) => {
  const { dataState } = state;
  const { rowKey } = action;
  const newDataState = new Map(dataState);

  const rowState = newDataState.get(rowKey);
  newDataState.set(rowKey, {
    ...rowState,
    isSelected: false,
  });

  let hasSelection = false;
  // eslint-disable-next-line no-restricted-syntax
  for (const row of newDataState.values()) {
    if (row.isSelected) {
      hasSelection = true;
      break;
    }
  }

  return { ...state, dataState: newDataState, hasSelection };
};

/**
 * Removes all rows from being selected.
 * @param {Object} state  The current state
 * Action: { type: 'deselectAll' }
 */
export const deselectAll = state => {
  const { dataState } = state;
  const newDataState = new Map(dataState);

  // eslint-disable-next-line no-restricted-syntax
  for (const [rowKey, rowState] of newDataState.entries()) {
    if (rowState.isSelected) {
      newDataState.set(rowKey, {
        ...rowState,
        isSelected: false,
      });
    }
  }
  return { ...state, dataState: newDataState, hasSelection: false };
};

/**
 * Focuses the cell provided in the action passed
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 * action: { type: 'focusCell', rowKey, columnKey }
 */
export const focusCell = (state, action) => {
  // Clear any existing focus and focus cell specified in action
  const { rowKey, columnKey } = action;
  return setFocus(state, rowKey, columnKey);
};

/**
 * Sorts the current set of data by the provided
 * key and direction in action.
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 * Action: { type: 'sortData', sortBy }
 * sortBy: String key of the field of the objects to sort by.
 */
export const sortData = (state, action) => {
  const { data, isAscending, sortBy } = state;
  const { sortBy: newSortBy } = action;

  // If the new sortBy is the same as the sortBy in state, then invert isAscending
  // that was set by the last sortBy action. Otherwise, default to true.
  const newIsAscending = newSortBy === sortBy ? !isAscending : true;

  const newData = newSortDataBy(data, newSortBy, newIsAscending);
  return { ...state, data: newData, sortBy: newSortBy, isAscending: newIsAscending };
};

/**
 * Opens a basic modal which does not require any other value
 * to be set upon opening. i.e. text editors
 *
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 * Action: { type: 'openBasicModal', modalKey }
 */
export const openBasicModal = (state, action) => {
  const { modalKey } = action;
  return { ...state, modalKey };
};

/**
 * Sets the modal open state to false, closing any
 * modal that is open.
 *
 * @param {Object} state  The current state
 * Action: { type: 'closeBasicModal' }
 */
export const closeBasicModal = state => ({ ...state, modalKey: '' });

/**
 * Adds all items from a master list to the pageObject held
 * in state - either a Requisition or Transaction.
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 * Action: { type: 'addMasterListItems', objectType }
 */
export const addMasterListItems = state => {
  const { backingData, isAscending, sortBy } = state;

  const newData = newSortDataBy(backingData.slice(), sortBy, isAscending);

  return { ...state, data: newData };
};

/**
 * Creates an Item (Either Requisition or Transaction), and appends
 * this item to the data array for a page.
 *
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 * Action: { type: 'addItem', item, addedItemType }
 */
export const addItem = (state, action) => {
  const { data } = state;
  const { item } = action;

  return { ...state, data: [item, ...data], modalKey: '', sortBy: '', searchTerm: '' };
};

/**
 * Reducer helper method for editing a non-setter field on a
 * realm object. Should be called by more explicit reducer
 * methods and not exported to avoid misuse. To create a reducer
 * method for setting a simple value for a realm object, create a
 * more explicit reducer method with logic specific to that field
 * contained, and call this method. See editTheirRef.
 *
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 * Action: { type: 'editPageObject', value, field, pageObjectType }
 */
const editPageObject = state => ({ ...state, modalKey: '' });

/**
 * Edits the passed pageObject 'theirRef' field with the value supplied.
 *
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 * Action: { type: 'editPageObject', value, pageObjectType }
 */
export const editTheirRef = (state, action) => {
  const { pageObject } = state;
  const { value } = action;

  const { theirRef } = pageObject;

  if (theirRef !== value) return { ...editPageObject(state, { ...action, field: 'theirRef' }) };
  return state;
};

/**
 * Edits the passed pageObject 'comment' field with the value supplied.
 *
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 * Action: { type: 'editPageObject', value, pageObjectType }
 */
export const editComment = (state, action) => {
  const { pageObject } = state;
  const { value } = action;

  const { comment } = pageObject;

  if (comment !== value) return { ...editPageObject(state, { ...action, field: 'comment' }) };
  return state;
};

/**
 * Removes the selected records from state. Where each selected
 * record is indicated by DataState[rowKey].isSelected. Thunks should have
 * handled the actual deleting of records before this is dispatched.
 *
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 */
export const deleteRecordsById = state => {
  const { data } = state;

  const newDataState = new Map();
  const newData = data.filter(record => record.isValid());

  return {
    ...state,
    data: newData,
    dataState: newDataState,
    hasSelection: false,
    modalKey: '',
  };
};

/**
 * Simply refresh's the data object in state to
 * correctly match the backingData when side effects
 * such as finalizing manipulate the state of a page
 * from outside the reducer. Should only be used when
 * there are no other options.
 *
 * @param {Object} state  The current state
 */
export const refreshData = state => {
  const { backingData } = state;
  return { ...state, data: backingData.slice() };
};

/**
 * Edits an expiry date for a Row in a DataTable.
 *
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 * Action: {type: 'editBatchExpiry', rowKey }
 */
export const editBatchExpiry = (state, action) => {
  const { rowKey } = action;
  const { dataState } = state;

  // Change object reference of row in `dataState` to trigger rerender of that row.
  // Realm object reference in `data` can't be affected in any tidy manner.
  const newDataState = new Map(dataState);
  const nextRowState = newDataState.get(rowKey);
  newDataState.set(rowKey, { ...nextRowState });

  return { ...state, dataState: newDataState };
};
<commit_msg>Add update to filterData reducer case<commit_after>/**
 * mSupply Mobile
 * Sustainable Solutions (NZ) Ltd. 2019
 */

import { newSortDataBy } from '../../../utilities';

/**
 * Immutably clears the current focus
 * @param {object} currState  the copy of state you want affected
 * @return {object}           New state with no cell focused
 */
const clearFocus = state => {
  const { dataState, currentFocusedRowKey } = state;
  if (!currentFocusedRowKey) {
    return state;
  }

  const newDataState = new Map(dataState);
  const currentRowState = newDataState.get(currentFocusedRowKey);
  newDataState.set(currentFocusedRowKey, {
    ...currentRowState,
    focusedColumn: null,
  });

  return { ...state, dataState: newDataState, currentFocusedRowKey: null };
};

/**
 * Immutably sets the current focus to the cell identified by `rowKey` and `columnKey`
 * @param {object} state  The copy of state to affect
 * @param {string} rowKey     The key of the row the cell to focus is in
 * @param {string} columnKey  The key of the column the cell to focus is in
 * @return {object}           A new object with a cell focused
 */
const setFocus = (state, rowKey, columnKey) => {
  const { dataState, currentFocusedRowKey } = state;
  const newDataState = new Map(dataState);

  // Clear previous focus if in a different row
  if (currentFocusedRowKey && rowKey !== currentFocusedRowKey) {
    const currentRowState = newDataState.get(currentFocusedRowKey);
    newDataState.set(currentFocusedRowKey, {
      ...currentRowState,
      focusedColumn: null,
    });
  }

  // Update focusedColumn in specified row
  const nextRowState = newDataState.get(rowKey);
  newDataState.set(rowKey, {
    ...nextRowState,
    focusedColumn: columnKey,
  });

  return {
    ...state,
    dataState: newDataState,
    currentFocusedRowKey: rowKey,
  };
};

/**
 *
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 */
export const filterData = (state, action) => {
  const { backingData, filterDataKeys, sortBy, isAscending } = state;
  const { searchTerm } = action;

  const queryString = filterDataKeys
    .map(filterTerm => `${filterTerm} CONTAINS[c]  $0`)
    .join(' OR ');

  const filteredData = backingData.filtered(queryString, searchTerm).slice();

  return {
    ...state,
    data: sortBy ? newSortDataBy(filteredData, sortBy, isAscending) : filteredData,
    searchTerm,
  };
};

export const editTotalQuantity = (state, action) => {
  const { rowKey } = action;
  const { dataState } = state;

  // Change object reference of row in `dataState` to trigger rerender of that row.
  // Realm object reference in `data` can't be affected in any tidy manner.
  const newDataState = new Map(dataState);
  const nextRowState = newDataState.get(rowKey);
  newDataState.set(rowKey, { ...nextRowState });

  return { ...state, dataState: newDataState };
};

/**
 * Focus the next appropriate cell after the current cell provided in action
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 */
export const focusNextCell = (state, action) => {
  const { data, columns, keyExtractor } = state;
  const { rowKey, columnKey } = action;

  // Handle finding next cell to focus
  let nextEditableColKey;
  const currentColIndex = columns.findIndex(col => col.key === columnKey);
  for (let index = currentColIndex + 1; index < columns.length; index++) {
    if (columns[index].type === 'editable') {
      nextEditableColKey = columns[index].key;
      break;
    }
  }

  if (nextEditableColKey) {
    // Focus next editable cell in row
    return setFocus(state, rowKey, nextEditableColKey);
  }

  // Attempt moving focus to next row
  const nextRowIndex = data.findIndex(row => keyExtractor(row) === rowKey) + 1;

  if (nextRowIndex < data.length) {
    // Focus first editable cell in next row
    const nextRowKey = keyExtractor(data[nextRowIndex]);
    const firstEditableColKey = columns.find(col => col.type === 'editable').key;
    return setFocus(state, nextRowKey, firstEditableColKey);
  }

  // We were on the last row and last column, so unfocus current cell
  return clearFocus(state);
};

/**
 * Sets the provided row in action as selected
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 * Action: { type: 'selectRow', rowKey }
 */
export const selectRow = (state, action) => {
  const { dataState } = state;
  const { rowKey } = action;
  const newDataState = new Map(dataState);

  const rowState = newDataState.get(rowKey);
  newDataState.set(rowKey, {
    ...rowState,
    isSelected: true,
  });

  return { ...state, dataState: newDataState, hasSelection: true };
};

/**
 * Removes the provided row in action from being
 * selected.
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 * Action: { type: 'deselectRow', rowKey }
 */
export const deselectRow = (state, action) => {
  const { dataState } = state;
  const { rowKey } = action;
  const newDataState = new Map(dataState);

  const rowState = newDataState.get(rowKey);
  newDataState.set(rowKey, {
    ...rowState,
    isSelected: false,
  });

  let hasSelection = false;
  // eslint-disable-next-line no-restricted-syntax
  for (const row of newDataState.values()) {
    if (row.isSelected) {
      hasSelection = true;
      break;
    }
  }

  return { ...state, dataState: newDataState, hasSelection };
};

/**
 * Removes all rows from being selected.
 * @param {Object} state  The current state
 * Action: { type: 'deselectAll' }
 */
export const deselectAll = state => {
  const { dataState } = state;
  const newDataState = new Map(dataState);

  // eslint-disable-next-line no-restricted-syntax
  for (const [rowKey, rowState] of newDataState.entries()) {
    if (rowState.isSelected) {
      newDataState.set(rowKey, {
        ...rowState,
        isSelected: false,
      });
    }
  }
  return { ...state, dataState: newDataState, hasSelection: false };
};

/**
 * Focuses the cell provided in the action passed
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 * action: { type: 'focusCell', rowKey, columnKey }
 */
export const focusCell = (state, action) => {
  // Clear any existing focus and focus cell specified in action
  const { rowKey, columnKey } = action;
  return setFocus(state, rowKey, columnKey);
};

/**
 * Sorts the current set of data by the provided
 * key and direction in action.
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 * Action: { type: 'sortData', sortBy }
 * sortBy: String key of the field of the objects to sort by.
 */
export const sortData = (state, action) => {
  const { data, isAscending, sortBy } = state;
  const { sortBy: newSortBy } = action;

  // If the new sortBy is the same as the sortBy in state, then invert isAscending
  // that was set by the last sortBy action. Otherwise, default to true.
  const newIsAscending = newSortBy === sortBy ? !isAscending : true;

  const newData = newSortDataBy(data, newSortBy, newIsAscending);
  return { ...state, data: newData, sortBy: newSortBy, isAscending: newIsAscending };
};

/**
 * Opens a basic modal which does not require any other value
 * to be set upon opening. i.e. text editors
 *
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 * Action: { type: 'openBasicModal', modalKey }
 */
export const openBasicModal = (state, action) => {
  const { modalKey } = action;
  return { ...state, modalKey };
};

/**
 * Sets the modal open state to false, closing any
 * modal that is open.
 *
 * @param {Object} state  The current state
 * Action: { type: 'closeBasicModal' }
 */
export const closeBasicModal = state => ({ ...state, modalKey: '' });

/**
 * Adds all items from a master list to the pageObject held
 * in state - either a Requisition or Transaction.
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 * Action: { type: 'addMasterListItems', objectType }
 */
export const addMasterListItems = state => {
  const { backingData, isAscending, sortBy } = state;

  const newData = newSortDataBy(backingData.slice(), sortBy, isAscending);

  return { ...state, data: newData };
};

/**
 * Creates an Item (Either Requisition or Transaction), and appends
 * this item to the data array for a page.
 *
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 * Action: { type: 'addItem', item, addedItemType }
 */
export const addItem = (state, action) => {
  const { backingData } = state;
  const { item } = action;

  return {
    ...state,
    data: [item, ...backingData.slice(0, backingData.length - 1)],
    modalKey: '',
    sortBy: '',
    searchTerm: '',
  };
};

/**
 * Reducer helper method for editing a non-setter field on a
 * realm object. Should be called by more explicit reducer
 * methods and not exported to avoid misuse. To create a reducer
 * method for setting a simple value for a realm object, create a
 * more explicit reducer method with logic specific to that field
 * contained, and call this method. See editTheirRef.
 *
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 * Action: { type: 'editPageObject', value, field, pageObjectType }
 */
const editPageObject = state => ({ ...state, modalKey: '' });

/**
 * Edits the passed pageObject 'theirRef' field with the value supplied.
 *
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 * Action: { type: 'editPageObject', value, pageObjectType }
 */
export const editTheirRef = (state, action) => {
  const { pageObject } = state;
  const { value } = action;

  const { theirRef } = pageObject;

  if (theirRef !== value) return { ...editPageObject(state, { ...action, field: 'theirRef' }) };
  return state;
};

/**
 * Edits the passed pageObject 'comment' field with the value supplied.
 *
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 * Action: { type: 'editPageObject', value, pageObjectType }
 */
export const editComment = (state, action) => {
  const { pageObject } = state;
  const { value } = action;

  const { comment } = pageObject;

  if (comment !== value) return { ...editPageObject(state, { ...action, field: 'comment' }) };
  return state;
};

/**
 * Removes the selected records from state. Where each selected
 * record is indicated by DataState[rowKey].isSelected. Thunks should have
 * handled the actual deleting of records before this is dispatched.
 *
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 */
export const deleteRecordsById = state => {
  const { data } = state;

  const newDataState = new Map();
  const newData = data.filter(record => record.isValid());

  return {
    ...state,
    data: newData,
    dataState: newDataState,
    hasSelection: false,
    modalKey: '',
  };
};

/**
 * Simply refresh's the data object in state to
 * correctly match the backingData when side effects
 * such as finalizing manipulate the state of a page
 * from outside the reducer. Should only be used when
 * there are no other options.
 *
 * @param {Object} state  The current state
 */
export const refreshData = state => {
  const { backingData } = state;
  return { ...state, data: backingData.slice() };
};

/**
 * Edits an expiry date for a Row in a DataTable.
 *
 * @param {Object} state  The current state
 * @param {Object} action The action to act upon
 * Action: {type: 'editBatchExpiry', rowKey }
 */
export const editBatchExpiry = (state, action) => {
  const { rowKey } = action;
  const { dataState } = state;

  // Change object reference of row in `dataState` to trigger rerender of that row.
  // Realm object reference in `data` can't be affected in any tidy manner.
  const newDataState = new Map(dataState);
  const nextRowState = newDataState.get(rowKey);
  newDataState.set(rowKey, { ...nextRowState });

  return { ...state, dataState: newDataState };
};
<|endoftext|>


<commit_before>describe('ContributionDetail model', function() {
  beforeAll(function(){
    this.contribution_mock = ContributionDetailMockery(1)[0];
    spyOn(m.postgrest, "requestWithToken");
  });

  describe('when instantiated', function() {
    beforeAll(function() {
      this.contribution = new adminApp.models.ContributionDetail(this.contribution_mock);
    });

    it('should exhibit attributes', function() {
      expect(this.contribution).toMatchPropertiesOf(this.contribution_mock);
    });
  });

  describe('fetching data', function() {
    it('should instantiate a get function', function() {
      expect(typeof adminApp.models.ContributionDetail.get).toBe('function');
    });
    it('should call requestWithToken when getting contributions', function() {
      adminApp.models.ContributionDetail.get();
      expect(m.postgrest.requestWithToken).toHaveBeenCalled();
    });
    it('should set a Range & Range-unit request header', function() {
      pending("Figure out a way to test xhr request by steps");
    });
  });

});<commit_msg>This test was moved to mithril.postgrest<commit_after>describe('ContributionDetail model', function() {
  beforeAll(function(){
    this.contribution_mock = ContributionDetailMockery(1)[0];
    spyOn(m.postgrest, "requestWithToken");
  });

  describe('when instantiated', function() {
    beforeAll(function() {
      this.contribution = new adminApp.models.ContributionDetail(this.contribution_mock);
    });

    it('should exhibit attributes', function() {
      expect(this.contribution).toMatchPropertiesOf(this.contribution_mock);
    });
  });
});
<|endoftext|>


<commit_before>'use strict';

const apiai = require('apiai');
const express = require('express');
const bodyParser = require('body-parser');
const uuid = require('node-uuid');
const request = require('request');

const REST_PORT = (process.env.PORT || 5000);
const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN;
const APIAI_LANG = process.env.APIAI_LANG || 'en';
const FB_VERIFY_TOKEN = process.env.FB_VERIFY_TOKEN;
const FB_PAGE_ACCESS_TOKEN = process.env.FB_PAGE_ACCESS_TOKEN;

const apiAiService = apiai(APIAI_ACCESS_TOKEN, {language: APIAI_LANG, requestSource: "fb"});
const sessionIds = new Map();

function processEvent(event) {
    var sender = event.sender.id;

    if (event.message && event.message.text) {
        var text = event.message.text;
        // Handle a text message from this sender

        if (!sessionIds.has(sender)) {
            sessionIds.set(sender, uuid.v1());
        }

        console.log("Text", text);
        var userName = "testUser";
        let apiaiRequest = apiAiService.textRequest(text,
            {
                sessionId: sessionIds.get(sender),
                contexts: [
                    {
                    name: "generic",
                    parameters: {
                          facebook_user: userName
                        }
                    }]
            });

        apiaiRequest.on('response', (response) => {
            if (isDefined(response.result)) {
                let responseText = response.result.fulfillment.speech;
                let responseData = response.result.fulfillment.data;
                let action = response.result.action;

                if (isDefined(responseData) && isDefined(responseData.facebook)) {
                    try {
                        console.log('Response as formatted message');
                        sendFBMessage(sender, responseData.facebook);
                    } catch (err) {
                        sendFBMessage(sender, {text: err.message });
                    }
                } else if (isDefined(responseText)) {
                    console.log('Response as text message');
                    sendFBMessage(sender, {text: responseText});
                }

            }
        });

        apiaiRequest.on('error', (error) => console.error(error));
        apiaiRequest.end();
    }
}

function sendFBMessage(sender, messageData) {

    var APISpeech = messageData.text;

    if(APISpeech == "structured"){
        messageData = {
            "attachment": {
              "type": "template",
              "payload": {
                "template_type": "generic",
                "elements": [{
                  "title": "First card",
                  "subtitle": "Element #1 of an hscroll",
                  "image_url": "http://messengerdemo.parseapp.com/img/rift.png",
                  "buttons": [{
                    "type": "web_url",
                    "url": "https://www.messenger.com/",
                    "title": "Web url"
                  }, {
                    "type": "postback",
                    "title": "Postback",
                    "payload": "Payload for first element in a generic bubble",
                  }],
                },{
                  "title": "Second card",
                  "subtitle": "Element #2 of an hscroll",
                  "image_url": "http://messengerdemo.parseapp.com/img/gearvr.png",
                  "buttons": [{
                    "type": "postback",
                    "title": "Postback",
                    "payload": "Payload for second element in a generic bubble",
                  }],
                }]
              }
            }
          };
    }
    var messageStructured =

    request({
        url: 'https://graph.facebook.com/v2.6/me/messages',
        qs: {access_token: FB_PAGE_ACCESS_TOKEN},
        method: 'POST',
        json: {
            recipient: {id: sender},
            message: messageData
        }
    }, function (error, response, body) {
        if (error) {
            console.log('Error sending message: ', error);
        } else if (response.body.error) {
            console.log('Error: ', response.body.error);
        }
    });
}

function doSubscribeRequest() {
    request({
            method: 'POST',
            uri: "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=" + FB_PAGE_ACCESS_TOKEN
        },
        function (error, response, body) {
            if (error) {
                console.error('Error while subscription: ', error);
            } else {
                console.log('Subscription result: ', response.body);
            }
        });
}

function isDefined(obj) {
    if (typeof obj == 'undefined') {
        return false;
    }

    if (!obj) {
        return false;
    }

    return obj != null;
}

const app = express();
app.use(bodyParser.json());
app.all('*', function (req, res, next) {
    // res.header("Access-Control-Allow-Origin", '*');
    // res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, content-type, accept");
    next();
});

app.get('/webhook/', function (req, res) {
    if (req.query['hub.verify_token'] == FB_VERIFY_TOKEN) {
        res.send(req.query['hub.challenge']);

        setTimeout(function () {
            doSubscribeRequest();
        }, 3000);
    } else {
        res.send('Error, wrong validation token');
    }
});

app.post('/webhook/', function (req, res) {
    try {
        var messaging_events = req.body.entry[0].messaging;
        for (var i = 0; i < messaging_events.length; i++) {
            var event = req.body.entry[0].messaging[i];
            processEvent(event);
        }
        return res.status(200).json({
            status: "ok"
        });
    } catch (err) {
        return res.status(400).json({
            status: "error",
            error: err
        });
    }

});

app.listen(REST_PORT, function () {
    console.log('Rest service ready on port ' + REST_PORT);
});

doSubscribeRequest();
<commit_msg>Update app.js<commit_after>'use strict';

const apiai = require('apiai');
const express = require('express');
const bodyParser = require('body-parser');
const uuid = require('node-uuid');
const request = require('request');

const REST_PORT = (process.env.PORT || 5000);
const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN;
const APIAI_LANG = process.env.APIAI_LANG || 'en';
const FB_VERIFY_TOKEN = process.env.FB_VERIFY_TOKEN;
const FB_PAGE_ACCESS_TOKEN = process.env.FB_PAGE_ACCESS_TOKEN;

const apiAiService = apiai(APIAI_ACCESS_TOKEN, {language: APIAI_LANG, requestSource: "fb"});
const sessionIds = new Map();

function processEvent(event) {
    var sender = event.sender.id;

    if (event.message && event.message.text) {
        var text = event.message.text;
        // Handle a text message from this sender

        if (!sessionIds.has(sender)) {
            sessionIds.set(sender, uuid.v1());
        }

        console.log("Text", text);
        var userName = "testUser";
        let apiaiRequest = apiAiService.textRequest(text,
            {
                sessionId: sessionIds.get(sender),
                contexts: [
                    {
                    name: "generic",
                    parameters: {
                          facebook_user: userName
                        }
                    }]
            });

        apiaiRequest.on('response', (response) => {
            if (isDefined(response.result)) {
                let responseText = response.result.fulfillment.speech;
                let responseData = response.result.fulfillment.data;
                let action = response.result.action;

                if (isDefined(responseData) && isDefined(responseData.facebook)) {
                    try {
                        console.log('Response as formatted message');
                        sendFBMessage(sender, responseData.facebook);
                    } catch (err) {
                        sendFBMessage(sender, {text: err.message });
                    }
                } else if (isDefined(responseText)) {
                    console.log('Response as text message');
                    sendFBMessage(sender, {text: responseText});
                }

            }
        });

        apiaiRequest.on('error', (error) => console.error(error));
        apiaiRequest.end();
    }
}

function sendFBMessage(sender, messageData) {

    var APISpeech = messageData.text;

    if(APISpeech == "structured"){
        messageData = {
            "attachment": {
              "type": "template",
              "payload": {
                "template_type": "generic",
                "elements": [{
                  "title": "First card",
                  "subtitle": "Element #1 of an hscroll",
                  "image_url": "http://messengerdemo.parseapp.com/img/rift.png",
                  "buttons": [{
                    "type": "web_url",
                    "url": "https://www.messenger.com/",
                    "title": "Web url"
                  }, {
                    "type": "postback",
                    "title": "Postback",
                    "payload": "Payload for first element in a generic bubble",
                  }],
                },{
                  "title": "Second card",
                  "subtitle": "Element #2 of an hscroll",
                  "image_url": "http://messengerdemo.parseapp.com/img/gearvr.png",
                  "buttons": [{
                    "type": "postback",
                    "title": "Postback",
                    "payload": "Payload for second element in a generic bubble",
                  }],
                }]
              }
            }
          };
    }

    request({
        url: 'https://graph.facebook.com/v2.6/me/messages',
        qs: {access_token: FB_PAGE_ACCESS_TOKEN},
        method: 'POST',
        json: {
            recipient: {id: sender},
            message: messageData
        }
    }, function (error, response, body) {
        if (error) {
            console.log('Error sending message: ', error);
        } else if (response.body.error) {
            console.log('Error: ', response.body.error);
        }
    });
}

function doSubscribeRequest() {
    request({
            method: 'POST',
            uri: "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=" + FB_PAGE_ACCESS_TOKEN
        },
        function (error, response, body) {
            if (error) {
                console.error('Error while subscription: ', error);
            } else {
                console.log('Subscription result: ', response.body);
            }
        });
}

function isDefined(obj) {
    if (typeof obj == 'undefined') {
        return false;
    }

    if (!obj) {
        return false;
    }

    return obj != null;
}

const app = express();
app.use(bodyParser.json());
app.all('*', function (req, res, next) {
    // res.header("Access-Control-Allow-Origin", '*');
    // res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, content-type, accept");
    next();
});

app.get('/webhook/', function (req, res) {
    if (req.query['hub.verify_token'] == FB_VERIFY_TOKEN) {
        res.send(req.query['hub.challenge']);

        setTimeout(function () {
            doSubscribeRequest();
        }, 3000);
    } else {
        res.send('Error, wrong validation token');
    }
});

app.post('/webhook/', function (req, res) {
    try {
        var messaging_events = req.body.entry[0].messaging;
        for (var i = 0; i < messaging_events.length; i++) {
            var event = req.body.entry[0].messaging[i];
            processEvent(event);
        }
        return res.status(200).json({
            status: "ok"
        });
    } catch (err) {
        return res.status(400).json({
            status: "error",
            error: err
        });
    }

});

app.listen(REST_PORT, function () {
    console.log('Rest service ready on port ' + REST_PORT);
});

doSubscribeRequest();
<|endoftext|>


<commit_before>
Elm.Native.Error = function(elm) {
    'use strict';
    elm.Native = elm.Native || {};
    if (elm.Native.Error) return elm.Native.Error;

    var fromString = Elm.Native.JavaScript(elm).fromString;

    function Case(moduleName, span) {
	var msg = 'Non-exhaustive pattern match in case expression in module '
	throw new Error(msg + moduleName + " (" + span + ")")
    }

    function If(moduleName, span) {
	var msg = 'Non-exhaustive pattern match in multi-way-if expression in module '
	throw new Error(msg + moduleName + " (" + span + ")")
    }

    function raise(str) { throw new Error(fromString(str)); }

    return elm.Native.Error = { Case: Case, If: If, raise: raise };
};<commit_msg>Better error messages for runtime errors in cases and ifs<commit_after>
Elm.Native.Error = function(elm) {
    'use strict';
    elm.Native = elm.Native || {};
    if (elm.Native.Error) return elm.Native.Error;

    var fromString = Elm.Native.JavaScript(elm).fromString;

    function indent(lines) {
        var msg = '';
        for (var i = 0; i < lines.length; ++i) {
            msg += '<br/>    ' + lines[i];
        }
        return msg;
    }

    function Case(moduleName, span) {
	var msg = indent(['Non-exhaustive pattern match in case-expression.',
                          'Make sure your patterns cover every case!']);
	throw new Error('Runtime error in module ' + moduleName + ' (' + span + '):' + msg);
    }

    function If(moduleName, span) {
	var msg = indent(['Non-exhaustive pattern match in multi-way-if expression.',
                          'It is best to use \'otherwise\' as the last branch of multi-way-if.']);
	throw new Error('Runtime error in module ' + moduleName + ' (' + span + '):' + msg);
    }

    function raise(str) { throw new Error(fromString(str)); }

    return elm.Native.Error = { Case: Case, If: If, raise: raise };
};<|endoftext|>


<commit_before>var express = require('express');
var app = express();
var yaml = require('js-yaml');
var fs = require('fs');
var util = require('util');
// Wooo. Colors.
var colors = require('colors');

app.use(express.json());
app.use(express.urlencoded());
app.use(app.router);

// @todo. Introduce more loggers.

// The following severities is available:
//   - i, w, e
app.log = function(str, severity) {
  var severityToColor = function(s, str) {
    if (s === 'w') {
      return str.yellow;
    }
    if (s === 'e') {
      return str.red;
    }
    return str.green;
  };
  if (!severity) {
    severity = 'info';
  }
  console.log(new Date().toString().yellow, severityToColor(severity, str));
};

// Read app config.
try {
  app.config = yaml.safeLoad(fs.readFileSync('../config.yml', 'utf8'));
}
catch(err) {
  app.log('No config.yml file found. Using default.config.yml for now. This is most likely not what you want to do.', 'w');
  app.config = yaml.safeLoad(fs.readFileSync('./default.config.yml', 'utf8'));
}

app.use(express.static(__dirname + '/../static'));

app.get('/', function(req, res){
  fs.readFile(__dirname + '/../static/index.html', 'utf8', function(err, text){
    console.log(err);
    res.send(text);
  });
});
app.start = function() {
  // Listen on selected port
  app.listen(app.config.port);
  app.log(util.format('Listening on port %d', app.config.port));
};
module.exports = app;
<commit_msg>Remove a console.log.<commit_after>var express = require('express');
var app = express();
var yaml = require('js-yaml');
var fs = require('fs');
var util = require('util');
// Wooo. Colors.
var colors = require('colors');

app.use(express.json());
app.use(express.urlencoded());
app.use(app.router);

// @todo. Introduce more loggers.

// The following severities is available:
//   - i, w, e
app.log = function(str, severity) {
  var severityToColor = function(s, str) {
    if (s === 'w') {
      return str.yellow;
    }
    if (s === 'e') {
      return str.red;
    }
    return str.green;
  };
  if (!severity) {
    severity = 'info';
  }
  console.log(new Date().toString().yellow, severityToColor(severity, str));
};

// Read app config.
try {
  app.config = yaml.safeLoad(fs.readFileSync('../config.yml', 'utf8'));
}
catch(err) {
  app.log('No config.yml file found. Using default.config.yml for now. This is most likely not what you want to do.', 'w');
  app.config = yaml.safeLoad(fs.readFileSync('./default.config.yml', 'utf8'));
}

app.use(express.static(__dirname + '/../static'));

app.get('/', function(req, res){
  fs.readFile(__dirname + '/../static/index.html', 'utf8', function(err, text){
    res.send(text);
  });
});
app.start = function() {
  // Listen on selected port
  app.listen(app.config.port);
  app.log(util.format('Listening on port %d', app.config.port));
};
module.exports = app;
<|endoftext|>


<commit_before>define([
  'frozen/box2d/BoxGame',
  'frozen/box2d/entities/Rectangle',
  'frozen/box2d/joints/Revolute'
], function(BoxGame, Rectangle, Revolute){

  'use strict';

  describe('BoxGame', function(){

    var game;
    var rect;
    var rect2;
    var joint;
    var joint2;

    beforeEach(function(){

      game = new BoxGame({
        canvas: document.createElement('canvas')
      });

      var rectJSON = {id: 'a', halfHeight: 5, halfWidth: 10, staticBody: false, x: 0, y: 0};
      var rectJSON2 = {id: 'b', halfHeight: 10, halfWidth: 5, staticBody: false, x: 0, y: 0};
      rect = new Rectangle(rectJSON);
      rect2 = new Rectangle(rectJSON2);

      var jointJSON = {id: 'j1', bodyId1: rect.id, bodyId2: rect2.id};
      var jointJSON2 = {id: 'j2', bodyId1: rect.id, bodyId2: rect2.id};
      joint = new Revolute(jointJSON);
      joint2 = new Revolute(jointJSON2);
    });

    afterEach(function(){
      game.stop();
    });

    it('should have an entities object by default', function(){
      expect(game.entities).not.toBeNull();
    });

    it('should have a joints object by default', function(){
      expect(game.joints).not.toBeNull();
    });

    it('should have a box object by default', function(){
      expect(game.box).not.toBeNull();
    });

    it('should have the box updating default', function(){
      expect(game.boxUpdating).toEqual(true);
    });

    it('should have functions defined', function(){
      expect(game.addBody).toBeDefined();
      expect(game.removeBody).toBeDefined();
      expect(game.addJoint).toBeDefined();
      expect(game.removeJoint).toBeDefined();
    });

    describe('Single Add & Removes', function(){

      beforeEach(function(){
        game.addBody(rect);
        game.addBody(rect2);
        game.addJoint(joint);
      });

      describe('BoxGame.addBody()', function(){

        it('should add a body to the box', function(){
          expect(game.entities[rect.id]).toBeDefined();
          expect(game.entities[rect.id]).toBe(rect);
        });

      });

      describe('BoxGame.removeBody()', function(){

        it('should remove a body from the box', function(){
          game.removeBody(rect);
          expect(game.entities[rect.id]).not.toBeDefined();
        });

      });

      describe('BoxGame.addJoint()', function(){

        it('should add a joint to the box', function(){
          expect(game.joints[joint.id]).toBeDefined();
          expect(game.joints[joint.id]).toBe(joint);
        });

      });

      describe('BoxGame.removeJoint()', function(){

        it('should remove a joint from the box', function(){
          game.removeJoint(joint);
          expect(game.joints[joint.id]).not.toBeDefined();
        });

      });

    });

    describe('Multi Add & Removes', function(){
      var bodies;
      var joints;

      beforeEach(function(){
        bodies = [rect, rect2];
        joints = [joint, joint2];
      });

      describe('BoxGame.addBodies()', function(){

        it('should take an array and add bodies to the box', function(){
          game.addBodies(bodies);
          expect(game.entities[rect.id]).toBeDefined();
          expect(game.entities[rect2.id]).toBeDefined();
          expect(game.entities[rect.id]).toBe(rect);
          expect(game.entities[rect2.id]).toBe(rect2);
        });

        it('should take any arguments and add bodies to the box', function(){
          game.addBodies(rect, rect2);
          expect(game.entities[rect.id]).toBeDefined();
          expect(game.entities[rect2.id]).toBeDefined();
          expect(game.entities[rect.id]).toBe(rect);
          expect(game.entities[rect2.id]).toBe(rect2);
        });

      });

      describe('BoxGame.removeBodies()', function(){

        it('should take an array and remove bodies from the box', function(){
          game.addBodies(bodies);
          game.removeBodies(bodies);
          expect(game.entities[rect.id]).not.toBeDefined();
          expect(game.entities[rect2.id]).not.toBeDefined();
        });

        it('should take any arguments and remove bodies from the box', function(){
          game.addBodies(bodies);
          game.removeBodies(rect, rect2);
          expect(game.entities[rect.id]).not.toBeDefined();
          expect(game.entities[rect2.id]).not.toBeDefined();
        });

      });

      describe('BoxGame.addJoints()', function(){

        it('should take an array and add joints to the box', function(){
          game.addJoints(joints);
          expect(game.joints[joint.id]).toBeDefined();
          expect(game.joints[joint2.id]).toBeDefined();
          expect(game.joints[joint.id]).toBe(joint);
          expect(game.joints[joint2.id]).toBe(joint2);
        });

        it('should take any arguments and add joints to the box', function(){
          game.addJoints(joint, joint2);
          expect(game.joints[joint.id]).toBeDefined();
          expect(game.joints[joint2.id]).toBeDefined();
          expect(game.joints[joint.id]).toBe(joint);
          expect(game.joints[joint2.id]).toBe(joint2);
        });

      });

      describe('BoxGame.removeJoints()', function(){

        it('should take an array and remove joints from the box', function(){
          game.addJoints(joints);
          game.removeJoints(joints);
          expect(game.joints[joint.id]).not.toBeDefined();
          expect(game.joints[joint2.id]).not.toBeDefined();
        });

        it('should take any arguments and remove joints from the box', function(){
          game.addJoints(joints);
          game.removeJoints(joint, joint2);
          expect(game.joints[joint.id]).not.toBeDefined();
          expect(game.joints[joint2.id]).not.toBeDefined();
        });

      });

    });

  });

});<commit_msg>beforeUpdate should be defined on BoxGame<commit_after>define([
  'frozen/box2d/BoxGame',
  'frozen/box2d/entities/Rectangle',
  'frozen/box2d/joints/Revolute'
], function(BoxGame, Rectangle, Revolute){

  'use strict';

  describe('BoxGame', function(){

    var game;
    var rect;
    var rect2;
    var joint;
    var joint2;

    beforeEach(function(){

      game = new BoxGame({
        canvas: document.createElement('canvas')
      });

      var rectJSON = {id: 'a', halfHeight: 5, halfWidth: 10, staticBody: false, x: 0, y: 0};
      var rectJSON2 = {id: 'b', halfHeight: 10, halfWidth: 5, staticBody: false, x: 0, y: 0};
      rect = new Rectangle(rectJSON);
      rect2 = new Rectangle(rectJSON2);

      var jointJSON = {id: 'j1', bodyId1: rect.id, bodyId2: rect2.id};
      var jointJSON2 = {id: 'j2', bodyId1: rect.id, bodyId2: rect2.id};
      joint = new Revolute(jointJSON);
      joint2 = new Revolute(jointJSON2);
    });

    afterEach(function(){
      game.stop();
    });

    it('should have an entities object by default', function(){
      expect(game.entities).not.toBeNull();
    });

    it('should have a joints object by default', function(){
      expect(game.joints).not.toBeNull();
    });

    it('should have a box object by default', function(){
      expect(game.box).not.toBeNull();
    });

    it('should have the box updating default', function(){
      expect(game.boxUpdating).toEqual(true);
    });

    it('should have functions defined', function(){
      expect(game.beforeUpdate).toBeDefined();
      expect(game.addBody).toBeDefined();
      expect(game.removeBody).toBeDefined();
      expect(game.addJoint).toBeDefined();
      expect(game.removeJoint).toBeDefined();
    });

    describe('Single Add & Removes', function(){

      beforeEach(function(){
        game.addBody(rect);
        game.addBody(rect2);
        game.addJoint(joint);
      });

      describe('BoxGame.addBody()', function(){

        it('should add a body to the box', function(){
          expect(game.entities[rect.id]).toBeDefined();
          expect(game.entities[rect.id]).toBe(rect);
        });

      });

      describe('BoxGame.removeBody()', function(){

        it('should remove a body from the box', function(){
          game.removeBody(rect);
          expect(game.entities[rect.id]).not.toBeDefined();
        });

      });

      describe('BoxGame.addJoint()', function(){

        it('should add a joint to the box', function(){
          expect(game.joints[joint.id]).toBeDefined();
          expect(game.joints[joint.id]).toBe(joint);
        });

      });

      describe('BoxGame.removeJoint()', function(){

        it('should remove a joint from the box', function(){
          game.removeJoint(joint);
          expect(game.joints[joint.id]).not.toBeDefined();
        });

      });

    });

    describe('Multi Add & Removes', function(){
      var bodies;
      var joints;

      beforeEach(function(){
        bodies = [rect, rect2];
        joints = [joint, joint2];
      });

      describe('BoxGame.addBodies()', function(){

        it('should take an array and add bodies to the box', function(){
          game.addBodies(bodies);
          expect(game.entities[rect.id]).toBeDefined();
          expect(game.entities[rect2.id]).toBeDefined();
          expect(game.entities[rect.id]).toBe(rect);
          expect(game.entities[rect2.id]).toBe(rect2);
        });

        it('should take any arguments and add bodies to the box', function(){
          game.addBodies(rect, rect2);
          expect(game.entities[rect.id]).toBeDefined();
          expect(game.entities[rect2.id]).toBeDefined();
          expect(game.entities[rect.id]).toBe(rect);
          expect(game.entities[rect2.id]).toBe(rect2);
        });

      });

      describe('BoxGame.removeBodies()', function(){

        it('should take an array and remove bodies from the box', function(){
          game.addBodies(bodies);
          game.removeBodies(bodies);
          expect(game.entities[rect.id]).not.toBeDefined();
          expect(game.entities[rect2.id]).not.toBeDefined();
        });

        it('should take any arguments and remove bodies from the box', function(){
          game.addBodies(bodies);
          game.removeBodies(rect, rect2);
          expect(game.entities[rect.id]).not.toBeDefined();
          expect(game.entities[rect2.id]).not.toBeDefined();
        });

      });

      describe('BoxGame.addJoints()', function(){

        it('should take an array and add joints to the box', function(){
          game.addJoints(joints);
          expect(game.joints[joint.id]).toBeDefined();
          expect(game.joints[joint2.id]).toBeDefined();
          expect(game.joints[joint.id]).toBe(joint);
          expect(game.joints[joint2.id]).toBe(joint2);
        });

        it('should take any arguments and add joints to the box', function(){
          game.addJoints(joint, joint2);
          expect(game.joints[joint.id]).toBeDefined();
          expect(game.joints[joint2.id]).toBeDefined();
          expect(game.joints[joint.id]).toBe(joint);
          expect(game.joints[joint2.id]).toBe(joint2);
        });

      });

      describe('BoxGame.removeJoints()', function(){

        it('should take an array and remove joints from the box', function(){
          game.addJoints(joints);
          game.removeJoints(joints);
          expect(game.joints[joint.id]).not.toBeDefined();
          expect(game.joints[joint2.id]).not.toBeDefined();
        });

        it('should take any arguments and remove joints from the box', function(){
          game.addJoints(joints);
          game.removeJoints(joint, joint2);
          expect(game.joints[joint.id]).not.toBeDefined();
          expect(game.joints[joint2.id]).not.toBeDefined();
        });

      });

    });

  });

});<|endoftext|>


<commit_before>import React from 'react'
import _ from 'lodash'
import injectSheet from 'react-jss'
import classNames from 'classnames'

import Spacer from '../../components/spacer'
import HospitalIcon from '../../components/icons/icon-components/hospital-icon'
import PregnancyIcon from '../../components/icons/icon-components/pregnancy-icon'
import { Phone, Desktop } from '../../components/breakpoints'

const resources = [
	{
		id: 'chc',
		name: 'Community Health Center',
	},
	{
		id: 'prc',
		name: 'Pregnancy Resource Center',
	},
]

const iconsPhone = [
	<HospitalIcon key={1} height={49} width={49} />,
	<PregnancyIcon key={2} height={49} width={49} />,
]
const iconsDesktop = [
	<HospitalIcon key={1} height={127} width={127} />,
	<PregnancyIcon key={2} height={127} width={127} />,
]

class ResourceCarousel extends React.Component {
	constructor(props) {
		super(props)
		this.state = {
			buttonClicked: null,
		}
		this.handleClick = this.handleClick.bind(this)
	}

	handleClick = resource => {
		this.setState({ buttonClicked: resource })
	}

	render() {
		const { classes } = this.props
		let { buttonClicked } = this.state

		return (

				{_.map(resources, (resource, index) => {
					const styleWithBorder = classNames(
						classes.border,
						classes.resourceBox,
					)

					let resourceBoxStyle =
						index === 1 ? styleWithBorder : classes.resourceBox

					if (resource.id === buttonClicked) {
						resourceBoxStyle = classNames(
							resourceBoxStyle,
							classes.buttonActiveState,
						)
					}

					return (
						<button
							className={resourceBoxStyle}
							key={resource.id}
							onClick={() => this.handleClick(resource.id)}
						>
							<Phone>{iconsPhone[index]}</Phone>
							<Desktop>{iconsDesktop[index]}</Desktop>
							<Spacer height="11px" />

{resource.name}

						</button>
					)
				})}

		)
	}
}

const styles = {
	resourceCarouselRoot: {
		display: 'flex',
		'justify-content': 'center',
	},
	resourceBox: {
		display: 'flex',
		'flex-direction': 'column',
		'justify-content': 'center',
		'align-items': 'center',
		height: '241px',
		width: '261px',
		cursor: 'pointer',
		outline: 'none',
		border: 'none',
		'&:hover': {
			'background-color': '#3D65F9',
			color: '#FFFFFF',
		},
	},
	buttonActiveState: {
		'background-color': '#3D65F9',
		color: '#FFFFFF',
	},
	resourceText: {
		'font-size': '24px',
		'text-align': 'center',
	},
	border: {
		'border-left': '3px solid black',
	},
}

export default injectSheet(styles)(ResourceCarousel)
<commit_msg>Add spacer<commit_after>import React from 'react'
import _ from 'lodash'
import injectSheet from 'react-jss'
import classNames from 'classnames'

import Spacer from '../../components/spacer'
import HospitalIcon from '../../components/icons/icon-components/hospital-icon'
import PregnancyIcon from '../../components/icons/icon-components/pregnancy-icon'
import { Phone, Desktop } from '../../components/breakpoints'

const resources = [
	{
		id: 'chc',
		name: 'Community Health Center',
	},
	{
		id: 'prc',
		name: 'Pregnancy Resource Center',
	},
]

const iconsPhone = [
	<HospitalIcon key={1} height={49} width={49} />,
	<PregnancyIcon key={2} height={49} width={49} />,
]
const iconsDesktop = [
	<HospitalIcon key={1} height={127} width={127} />,
	<PregnancyIcon key={2} height={127} width={127} />,
]

class ResourceCarousel extends React.Component {
	constructor(props) {
		super(props)
		this.state = {
			buttonClicked: null,
		}
		this.handleClick = this.handleClick.bind(this)
	}

	handleClick = resource => {
		this.setState({ buttonClicked: resource })
	}

	render() {
		const { classes } = this.props
		let { buttonClicked } = this.state

		return (

				{_.map(resources, (resource, index) => {
					const styleWithBorder = classNames(
						classes.border,
						classes.resourceBox,
					)

					let resourceBoxStyle =
						index === 1 ? styleWithBorder : classes.resourceBox

					if (resource.id === buttonClicked) {
						resourceBoxStyle = classNames(
							resourceBoxStyle,
							classes.buttonActiveState,
						)
					}

					return (
						<button
							className={resourceBoxStyle}
							key={resource.id}
							onClick={() => this.handleClick(resource.id)}
						>
							<Phone>

									{iconsPhone[index]}
									<Spacer height="9px" />

							</Phone>

							<Desktop>

									{iconsDesktop[index]}
									<Spacer height="20px" />

							</Desktop>

{resource.name}

						</button>
					)
				})}

		)
	}
}

const styles = {
	resourceCarouselRoot: {
		display: 'flex',
		'justify-content': 'center',
	},
	resourceBox: {
		display: 'flex',
		'flex-direction': 'column',
		'justify-content': 'center',
		'align-items': 'center',
		height: '241px',
		width: '261px',
		cursor: 'pointer',
		outline: 'none',
		border: 'none',
		'&:hover': {
			'background-color': '#3D65F9',
			color: '#FFFFFF',
		},
	},
	buttonActiveState: {
		'background-color': '#3D65F9',
		color: '#FFFFFF',
	},
	resourceText: {
		'font-size': '24px',
		'text-align': 'center',
	},
	border: {
		'border-left': '3px solid black',
	},
}

export default injectSheet(styles)(ResourceCarousel)
<|endoftext|>