diff --git a/app/javascript/packs/components/EditPopup/EditPopup.js b/app/javascript/packs/components/EditPopup/EditPopup.js
index b69bf69..a14bbe5 100644
--- a/app/javascript/packs/components/EditPopup/EditPopup.js
+++ b/app/javascript/packs/components/EditPopup/EditPopup.js
@@ -1,5 +1,5 @@
import React, { useEffect, useState } from 'react';
-import { isNil } from 'ramda';
+import { isNil, has } from 'ramda';
import Button from '@material-ui/core/Button';
import Card from '@material-ui/core/Card';
@@ -14,6 +14,8 @@ import PropTypes from 'prop-types';
import Form from './components/Form';
import TaskPresenter from 'presenters/TaskPresenter';
+import ImageUpload from 'packs/components/ImageUpload';
+import TasksRepository from 'repositories/TasksRepository';
import useStyles from './useStyles';
@@ -27,6 +29,14 @@ function EditPopup({ cardId, onClose, onCardDestroy, onCardLoad, onCardUpdate })
onCardLoad(cardId).then(setTask);
}, []);
+ const onRemoveImage = () => {
+ TasksRepository.removeImage(task.id);
+ };
+
+ const onAttachImage = (attachment) => {
+ TasksRepository.attachImage(attachment, task.id);
+ };
+
const handleCardUpdate = () => {
setSaving(true);
@@ -49,6 +59,7 @@ function EditPopup({ cardId, onClose, onCardDestroy, onCardLoad, onCardUpdate })
alert(`Destrucion Failed! Error: ${error.message}`);
});
};
+
const isLoading = isNil(task);
return (
@@ -84,6 +95,20 @@ function EditPopup({ cardId, onClose, onCardDestroy, onCardLoad, onCardUpdate })
>
Destroy
+ {isNil(TaskPresenter.imageUrl(task)) ? (
+
+
+
+ ) : (
+
+
+
+
+
+
+ )}
diff --git a/app/javascript/packs/components/EditPopup/useStyles.js b/app/javascript/packs/components/EditPopup/useStyles.js
index 01fdc0b..ca9459f 100644
--- a/app/javascript/packs/components/EditPopup/useStyles.js
+++ b/app/javascript/packs/components/EditPopup/useStyles.js
@@ -21,6 +21,14 @@ const useStyles = makeStyles(() => ({
display: 'flex',
justifyContent: 'flex-end',
},
+
+ imageUploadContainer: {
+ display: 'flex',
+ },
+
+ previewContainer: {
+ display: 'flex',
+ },
}));
export default useStyles;
diff --git a/app/javascript/packs/components/ImageUpload/ImageUpload.js b/app/javascript/packs/components/ImageUpload/ImageUpload.js
new file mode 100644
index 0000000..253d605
--- /dev/null
+++ b/app/javascript/packs/components/ImageUpload/ImageUpload.js
@@ -0,0 +1,96 @@
+import React, { useState } from 'react';
+import PropTypes from 'prop-types';
+import { isNil, path } from 'ramda';
+import Button from '@material-ui/core/Button';
+import ReactCrop, { makeAspectCrop } from 'react-image-crop';
+import 'react-image-crop/dist/ReactCrop.css';
+
+import useStyles from './useStyles';
+
+function ImageUpload({ onUpload }) {
+ const styles = useStyles();
+
+ const DEFAULT_CROP_PARAMS = {
+ units: 'px',
+ x: 0,
+ y: 0,
+ width: 100,
+ height: 100,
+ };
+
+ const [fileAsBase64, changeFileAsBase64] = useState(null);
+ const [cropParams, changeCropParams] = useState(DEFAULT_CROP_PARAMS);
+ const [file, changeFile] = useState(null);
+ const [image, changeImage] = useState(null);
+
+ const handleCropComplete = (newCrop, newPercentageCrop) => {
+ changeCropParams(newPercentageCrop);
+ };
+
+ const onImageLoaded = (loadedImage) => {
+ const newCropParams = makeAspectCrop(DEFAULT_CROP_PARAMS, loadedImage.width, loadedImage.height);
+ changeCropParams(newCropParams);
+ changeImage(loadedImage);
+ };
+
+ const getActualCropParameters = (width, height, params) => ({
+ cropX: (params.x * width) / 100,
+ cropY: (params.y * height) / 100,
+ cropWidth: (params.width * width) / 100,
+ cropHeight: (params.height * height) / 100,
+ });
+
+ const handleCropChange = (_, newCropParams) => {
+ changeCropParams(newCropParams);
+ };
+
+ const handleSave = () => {
+ const { naturalWidth: width, naturalHeight: height } = image;
+ const actualCropParams = getActualCropParameters(width, height, cropParams);
+ onUpload({ attachment: { ...actualCropParams, image: file } });
+ };
+
+ const handleImageRead = (newImage) => changeFileAsBase64(path(['target', 'result'], newImage));
+
+ const handleLoadFile = (e) => {
+ e.preventDefault();
+
+ const [acceptedFile] = e.target.files;
+
+ const fileReader = new FileReader();
+ fileReader.onload = handleImageRead;
+ fileReader.readAsDataURL(acceptedFile);
+ changeFile(acceptedFile);
+ };
+
+ return fileAsBase64 ? (
+ <>
+
+
+
+
+ >
+ ) : (
+
+ );
+}
+
+ImageUpload.propTypes = {
+ onUpload: PropTypes.func.isRequired,
+};
+
+export default ImageUpload;
diff --git a/app/javascript/packs/components/ImageUpload/index.js b/app/javascript/packs/components/ImageUpload/index.js
new file mode 100644
index 0000000..b3a99c0
--- /dev/null
+++ b/app/javascript/packs/components/ImageUpload/index.js
@@ -0,0 +1,3 @@
+import ImageUpload from './ImageUpload';
+
+export default ImageUpload;
diff --git a/app/javascript/packs/components/ImageUpload/useStyles.js b/app/javascript/packs/components/ImageUpload/useStyles.js
new file mode 100644
index 0000000..cb5f6d8
--- /dev/null
+++ b/app/javascript/packs/components/ImageUpload/useStyles.js
@@ -0,0 +1,13 @@
+import { makeStyles } from '@material-ui/core';
+
+const useStyles = makeStyles(() => ({
+ crop: {
+ maxHeight: 500,
+ maxWidth: 500,
+ position: 'absolute',
+ top: '35%',
+ left: '33%',
+ },
+}));
+
+export default useStyles;
diff --git a/app/javascript/presenters/TaskPresenter.js b/app/javascript/presenters/TaskPresenter.js
index 6765c58..1536293 100644
--- a/app/javascript/presenters/TaskPresenter.js
+++ b/app/javascript/presenters/TaskPresenter.js
@@ -10,6 +10,7 @@ export default new PropTypesPresenter(
assignee: PropTypes.object,
transitions: PropTypes.array,
state: PropTypes.string,
+ imageUrl: PropTypes.string,
},
{
title(task) {
diff --git a/app/javascript/repositories/TasksRepository.js b/app/javascript/repositories/TasksRepository.js
index f4d251a..0f5653f 100644
--- a/app/javascript/repositories/TasksRepository.js
+++ b/app/javascript/repositories/TasksRepository.js
@@ -26,4 +26,14 @@ export default {
const path = routes.apiV1TaskPath(id);
return FetchHelper.delete(path);
},
+
+ attachImage(attachment, id) {
+ const path = routes.attachImageApiV1TaskPath(id);
+ return FetchHelper.putFormData(path, attachment);
+ },
+
+ removeImage(id) {
+ const path = routes.removeImageApiV1TaskPath(id);
+ return FetchHelper.delete(path);
+ },
};
diff --git a/app/javascript/routes/ApiRoutes.js b/app/javascript/routes/ApiRoutes.js
index 6358236..12cb024 100644
--- a/app/javascript/routes/ApiRoutes.js
+++ b/app/javascript/routes/ApiRoutes.js
@@ -3,500 +3,500 @@
* Based on Rails 6.0.6 routes of App::Application
*/
const __jsr = (() => {
- const hasProp = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
- let NodeTypes;
- (function (NodeTypes) {
- NodeTypes[NodeTypes["GROUP"] = 1] = "GROUP";
- NodeTypes[NodeTypes["CAT"] = 2] = "CAT";
- NodeTypes[NodeTypes["SYMBOL"] = 3] = "SYMBOL";
- NodeTypes[NodeTypes["OR"] = 4] = "OR";
- NodeTypes[NodeTypes["STAR"] = 5] = "STAR";
- NodeTypes[NodeTypes["LITERAL"] = 6] = "LITERAL";
- NodeTypes[NodeTypes["SLASH"] = 7] = "SLASH";
- NodeTypes[NodeTypes["DOT"] = 8] = "DOT";
- })(NodeTypes || (NodeTypes = {}));
- const isBrowser = typeof window !== "undefined";
- const ModuleReferences = {
- CJS: {
- define(routes) {
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- module.exports = routes;
- },
- isSupported() {
- return typeof module === "object";
- },
- },
- AMD: {
- define(routes) {
- // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
- define([], function () {
- return routes;
- });
- },
- isSupported() {
- return typeof define === "function" && !!define.amd;
- },
- },
- UMD: {
- define(routes) {
- if (ModuleReferences.AMD.isSupported()) {
- ModuleReferences.AMD.define(routes);
- }
- else {
- if (ModuleReferences.CJS.isSupported()) {
- try {
- ModuleReferences.CJS.define(routes);
- }
- catch (error) {
- if (error.name !== "TypeError")
- throw error;
- }
- }
- }
- },
- isSupported() {
- return (ModuleReferences.AMD.isSupported() ||
- ModuleReferences.CJS.isSupported());
- },
- },
- ESM: {
- define() {
- // Module can only be defined using ruby code generation
- },
- isSupported() {
- // Its impossible to check if "export" keyword is supported
- return true;
- },
- },
- NIL: {
- define() {
- // Defined using const __jsr =
- },
- isSupported() {
- return true;
- },
- },
- DTS: {
- // Acts the same as ESM
- define(routes) {
- ModuleReferences.ESM.define(routes);
- },
- isSupported() {
- return ModuleReferences.ESM.isSupported();
- },
- },
- };
- class ParametersMissing extends Error {
- constructor(...keys) {
- super(`Route missing required keys: ${keys.join(", ")}`);
- this.keys = keys;
- Object.setPrototypeOf(this, Object.getPrototypeOf(this));
- this.name = ParametersMissing.name;
- }
- }
- const UriEncoderSegmentRegex = /[^a-zA-Z0-9\-._~!$&'()*+,;=:@]/g;
- const ReservedOptions = [
- "anchor",
- "trailing_slash",
- "subdomain",
- "host",
- "port",
- "protocol",
- ];
- class UtilsClass {
- constructor() {
- this.configuration = {
- prefix: "",
- default_url_options: {},
- special_options_key: "_options",
- serializer: null || this.default_serializer.bind(this),
- };
- }
- default_serializer(value, prefix) {
- if (this.is_nullable(value)) {
- return "";
- }
- if (!prefix && !this.is_object(value)) {
- throw new Error("Url parameters should be a javascript hash");
- }
- prefix = prefix || "";
- const result = [];
- if (this.is_array(value)) {
- for (const element of value) {
- result.push(this.default_serializer(element, prefix + "[]"));
- }
- }
- else if (this.is_object(value)) {
- for (let key in value) {
- if (!hasProp(value, key))
- continue;
- let prop = value[key];
- if (this.is_nullable(prop) && prefix) {
- prop = "";
- }
- if (this.is_not_nullable(prop)) {
- if (prefix) {
- key = prefix + "[" + key + "]";
- }
- result.push(this.default_serializer(prop, key));
- }
- }
- }
- else {
- if (this.is_not_nullable(value)) {
- result.push(encodeURIComponent(prefix) + "=" + encodeURIComponent("" + value));
- }
- }
- return result.join("&");
- }
- serialize(object) {
- return this.configuration.serializer(object);
- }
- extract_options(number_of_params, args) {
- const last_el = args[args.length - 1];
- if ((args.length > number_of_params && last_el === 0) ||
- (this.is_object(last_el) &&
- !this.looks_like_serialized_model(last_el))) {
- if (this.is_object(last_el)) {
- delete last_el[this.configuration.special_options_key];
- }
- return {
- args: args.slice(0, args.length - 1),
- options: last_el,
- };
- }
- else {
- return { args, options: {} };
- }
- }
- looks_like_serialized_model(object) {
- return (this.is_object(object) &&
- !(this.configuration.special_options_key in object) &&
- ("id" in object || "to_param" in object || "toParam" in object));
- }
- path_identifier(object) {
- const result = this.unwrap_path_identifier(object);
- return this.is_nullable(result) || result === false ? "" : "" + result;
- }
- unwrap_path_identifier(object) {
- let result = object;
- if (!this.is_object(object)) {
- return object;
- }
- if ("to_param" in object) {
- result = object.to_param;
- }
- else if ("toParam" in object) {
- result = object.toParam;
- }
- else if ("id" in object) {
- result = object.id;
- }
- else {
- result = object;
- }
- return this.is_callable(result) ? result.call(object) : result;
+ const hasProp = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
+ let NodeTypes;
+ (function (NodeTypes) {
+ NodeTypes[NodeTypes["GROUP"] = 1] = "GROUP";
+ NodeTypes[NodeTypes["CAT"] = 2] = "CAT";
+ NodeTypes[NodeTypes["SYMBOL"] = 3] = "SYMBOL";
+ NodeTypes[NodeTypes["OR"] = 4] = "OR";
+ NodeTypes[NodeTypes["STAR"] = 5] = "STAR";
+ NodeTypes[NodeTypes["LITERAL"] = 6] = "LITERAL";
+ NodeTypes[NodeTypes["SLASH"] = 7] = "SLASH";
+ NodeTypes[NodeTypes["DOT"] = 8] = "DOT";
+ })(NodeTypes || (NodeTypes = {}));
+ const isBrowser = typeof window !== "undefined";
+ const ModuleReferences = {
+ CJS: {
+ define(routes) {
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ module.exports = routes;
+ },
+ isSupported() {
+ return typeof module === "object";
+ },
+ },
+ AMD: {
+ define(routes) {
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
+ define([], function () {
+ return routes;
+ });
+ },
+ isSupported() {
+ return typeof define === "function" && !!define.amd;
+ },
+ },
+ UMD: {
+ define(routes) {
+ if (ModuleReferences.AMD.isSupported()) {
+ ModuleReferences.AMD.define(routes);
+ }
+ else {
+ if (ModuleReferences.CJS.isSupported()) {
+ try {
+ ModuleReferences.CJS.define(routes);
+ }
+ catch (error) {
+ if (error.name !== "TypeError")
+ throw error;
+ }
+ }
+ }
+ },
+ isSupported() {
+ return (ModuleReferences.AMD.isSupported() ||
+ ModuleReferences.CJS.isSupported());
+ },
+ },
+ ESM: {
+ define() {
+ // Module can only be defined using ruby code generation
+ },
+ isSupported() {
+ // Its impossible to check if "export" keyword is supported
+ return true;
+ },
+ },
+ NIL: {
+ define() {
+ // Defined using const __jsr =
+ },
+ isSupported() {
+ return true;
+ },
+ },
+ DTS: {
+ // Acts the same as ESM
+ define(routes) {
+ ModuleReferences.ESM.define(routes);
+ },
+ isSupported() {
+ return ModuleReferences.ESM.isSupported();
+ },
+ },
+ };
+ class ParametersMissing extends Error {
+ constructor(...keys) {
+ super(`Route missing required keys: ${keys.join(", ")}`);
+ this.keys = keys;
+ Object.setPrototypeOf(this, Object.getPrototypeOf(this));
+ this.name = ParametersMissing.name;
+ }
}
- partition_parameters(parts, required_params, default_options, call_arguments) {
- // eslint-disable-next-line prefer-const
- let { args, options } = this.extract_options(parts.length, call_arguments);
- if (args.length > parts.length) {
- throw new Error("Too many parameters provided for path");
- }
- let use_all_parts = args.length > required_params.length;
- const parts_options = {
- ...this.configuration.default_url_options,
- };
- for (const key in options) {
- const value = options[key];
- if (!hasProp(options, key))
- continue;
- use_all_parts = true;
- if (parts.includes(key)) {
- parts_options[key] = value;
- }
- }
- options = {
- ...this.configuration.default_url_options,
- ...default_options,
- ...options,
- };
- const keyword_parameters = {};
- let query_parameters = {};
- for (const key in options) {
- if (!hasProp(options, key))
- continue;
- const value = options[key];
- if (key === "params") {
- if (this.is_object(value)) {
- query_parameters = {
- ...query_parameters,
- ...value,
+ const UriEncoderSegmentRegex = /[^a-zA-Z0-9\-._~!$&'()*+,;=:@]/g;
+ const ReservedOptions = [
+ "anchor",
+ "trailing_slash",
+ "subdomain",
+ "host",
+ "port",
+ "protocol",
+ ];
+ class UtilsClass {
+ constructor() {
+ this.configuration = {
+ prefix: "",
+ default_url_options: {},
+ special_options_key: "_options",
+ serializer: null || this.default_serializer.bind(this),
};
- }
- else {
- throw new Error("params value should always be an object");
- }
- }
- else if (this.is_reserved_option(key)) {
- keyword_parameters[key] = value;
- }
- else {
- if (!this.is_nullable(value) &&
- (value !== default_options[key] || required_params.includes(key))) {
- query_parameters[key] = value;
- }
- }
- }
- const route_parts = use_all_parts ? parts : required_params;
- let i = 0;
- for (const part of route_parts) {
- if (i < args.length) {
- const value = args[i];
- if (!hasProp(parts_options, part)) {
- query_parameters[part] = value;
- ++i;
- }
- }
- }
- return { keyword_parameters, query_parameters };
- }
- build_route(parts, required_params, default_options, route, absolute, args) {
- const { keyword_parameters, query_parameters, } = this.partition_parameters(parts, required_params, default_options, args);
- const missing_params = required_params.filter((param) => !hasProp(query_parameters, param) ||
- this.is_nullable(query_parameters[param]));
- if (missing_params.length) {
- throw new ParametersMissing(...missing_params);
- }
- let result = this.get_prefix() + this.visit(route, query_parameters);
- if (keyword_parameters.trailing_slash) {
- result = result.replace(/(.*?)[/]?$/, "$1/");
- }
- const url_params = this.serialize(query_parameters);
- if (url_params.length) {
- result += "?" + url_params;
- }
- result += keyword_parameters.anchor
- ? "#" + keyword_parameters.anchor
- : "";
- if (absolute) {
- result = this.route_url(keyword_parameters) + result;
- }
- return result;
- }
- visit(route, parameters, optional = false) {
- switch (route[0]) {
- case NodeTypes.GROUP:
- return this.visit(route[1], parameters, true);
- case NodeTypes.CAT:
- return this.visit_cat(route, parameters, optional);
- case NodeTypes.SYMBOL:
- return this.visit_symbol(route, parameters, optional);
- case NodeTypes.STAR:
- return this.visit_globbing(route[1], parameters, true);
- case NodeTypes.LITERAL:
- case NodeTypes.SLASH:
- case NodeTypes.DOT:
- return route[1];
- default:
- throw new Error("Unknown Rails node type");
- }
- }
- is_not_nullable(object) {
- return !this.is_nullable(object);
- }
- is_nullable(object) {
- return object === undefined || object === null;
- }
- visit_cat(
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- [_type, left, right], parameters, optional) {
- const left_part = this.visit(left, parameters, optional);
- let right_part = this.visit(right, parameters, optional);
- if (optional &&
- ((this.is_optional_node(left[0]) && !left_part) ||
- (this.is_optional_node(right[0]) && !right_part))) {
- return "";
- }
- // if left_part ends on '/' and right_part starts on '/'
- if (left_part[left_part.length - 1] === "/" && right_part[0] === "/") {
- // strip slash from right_part
- // to prevent double slash
- right_part = right_part.substring(1);
- }
- return left_part + right_part;
- }
- visit_symbol(
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
- [_type, key], parameters, optional) {
- const value = this.path_identifier(parameters[key]);
- delete parameters[key];
- if (value.length) {
- return this.encode_segment(value);
- }
- if (optional) {
- return "";
- }
- else {
- throw new ParametersMissing(key);
- }
- }
- encode_segment(segment) {
- return segment.replace(UriEncoderSegmentRegex, (str) => encodeURIComponent(str));
- }
- is_optional_node(node) {
- return [NodeTypes.STAR, NodeTypes.SYMBOL, NodeTypes.CAT].includes(node);
- }
- build_path_spec(route, wildcard = false) {
- let key;
- switch (route[0]) {
- case NodeTypes.GROUP:
- return "(" + this.build_path_spec(route[1]) + ")";
- case NodeTypes.CAT:
- return (this.build_path_spec(route[1]) + this.build_path_spec(route[2]));
- case NodeTypes.STAR:
- return this.build_path_spec(route[1], true);
- case NodeTypes.SYMBOL:
- key = route[1];
- if (wildcard) {
- return (key.startsWith("*") ? "" : "*") + key;
- }
- else {
- return ":" + key;
- }
- break;
- case NodeTypes.SLASH:
- case NodeTypes.DOT:
- case NodeTypes.LITERAL:
- return route[1];
- default:
- throw new Error("Unknown Rails node type");
- }
- }
- visit_globbing(route, parameters, optional) {
- const key = route[1];
- let value = parameters[key];
- delete parameters[key];
- if (this.is_nullable(value)) {
- return this.visit(route, parameters, optional);
- }
- if (this.is_array(value)) {
- value = value.join("/");
- }
- const result = this.path_identifier(value);
- return false
- ? result
- : encodeURI(result);
- }
- get_prefix() {
- const prefix = this.configuration.prefix;
- return prefix.match("/$")
- ? prefix.substring(0, prefix.length - 1)
- : prefix;
- }
- route(parts_table, route_spec, absolute = false) {
- const required_params = [];
- const parts = [];
- const default_options = {};
- for (const [part, { r: required, d: value }] of Object.entries(parts_table)) {
- parts.push(part);
- if (required) {
- required_params.push(part);
- }
- if (this.is_not_nullable(value)) {
- default_options[part] = value;
- }
- }
- const result = (...args) => {
- return this.build_route(parts, required_params, default_options, route_spec, absolute, args);
- };
- result.requiredParams = () => required_params;
- result.toString = () => {
- return this.build_path_spec(route_spec);
- };
- return result;
- }
- route_url(route_defaults) {
- const hostname = route_defaults.host || this.current_host();
- if (!hostname) {
- return "";
- }
- const subdomain = route_defaults.subdomain
- ? route_defaults.subdomain + "."
- : "";
- const protocol = route_defaults.protocol || this.current_protocol();
- let port = route_defaults.port ||
- (!route_defaults.host ? this.current_port() : undefined);
- port = port ? ":" + port : "";
- return protocol + "://" + subdomain + hostname + port;
- }
- current_host() {
- var _a;
- return (isBrowser && ((_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.hostname)) || "";
- }
- current_protocol() {
- var _a, _b;
- return ((isBrowser && ((_b = (_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.protocol) === null || _b === void 0 ? void 0 : _b.replace(/:$/, ""))) || "http");
- }
- current_port() {
- var _a;
- return (isBrowser && ((_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.port)) || "";
- }
- is_object(value) {
- return (typeof value === "object" &&
- Object.prototype.toString.call(value) === "[object Object]");
- }
- is_array(object) {
- return object instanceof Array;
- }
- is_callable(object) {
- return typeof object === "function" && !!object.call;
- }
- is_reserved_option(key) {
- return ReservedOptions.includes(key);
- }
- configure(new_config) {
- this.configuration = { ...this.configuration, ...new_config };
- return this.configuration;
- }
- config() {
- return { ...this.configuration };
- }
- is_module_supported(name) {
- return ModuleReferences[name].isSupported();
- }
- ensure_module_supported(name) {
- if (!this.is_module_supported(name)) {
- throw new Error(`${name} is not supported by runtime`);
- }
- }
- define_module(name, module) {
- this.ensure_module_supported(name);
- ModuleReferences[name].define(module);
+ }
+ default_serializer(value, prefix) {
+ if (this.is_nullable(value)) {
+ return "";
+ }
+ if (!prefix && !this.is_object(value)) {
+ throw new Error("Url parameters should be a javascript hash");
+ }
+ prefix = prefix || "";
+ const result = [];
+ if (this.is_array(value)) {
+ for (const element of value) {
+ result.push(this.default_serializer(element, prefix + "[]"));
+ }
+ }
+ else if (this.is_object(value)) {
+ for (let key in value) {
+ if (!hasProp(value, key))
+ continue;
+ let prop = value[key];
+ if (this.is_nullable(prop) && prefix) {
+ prop = "";
+ }
+ if (this.is_not_nullable(prop)) {
+ if (prefix) {
+ key = prefix + "[" + key + "]";
+ }
+ result.push(this.default_serializer(prop, key));
+ }
+ }
+ }
+ else {
+ if (this.is_not_nullable(value)) {
+ result.push(encodeURIComponent(prefix) + "=" + encodeURIComponent("" + value));
+ }
+ }
+ return result.join("&");
+ }
+ serialize(object) {
+ return this.configuration.serializer(object);
+ }
+ extract_options(number_of_params, args) {
+ const last_el = args[args.length - 1];
+ if ((args.length > number_of_params && last_el === 0) ||
+ (this.is_object(last_el) &&
+ !this.looks_like_serialized_model(last_el))) {
+ if (this.is_object(last_el)) {
+ delete last_el[this.configuration.special_options_key];
+ }
+ return {
+ args: args.slice(0, args.length - 1),
+ options: last_el,
+ };
+ }
+ else {
+ return { args, options: {} };
+ }
+ }
+ looks_like_serialized_model(object) {
+ return (this.is_object(object) &&
+ !(this.configuration.special_options_key in object) &&
+ ("id" in object || "to_param" in object || "toParam" in object));
+ }
+ path_identifier(object) {
+ const result = this.unwrap_path_identifier(object);
+ return this.is_nullable(result) || result === false ? "" : "" + result;
+ }
+ unwrap_path_identifier(object) {
+ let result = object;
+ if (!this.is_object(object)) {
+ return object;
+ }
+ if ("to_param" in object) {
+ result = object.to_param;
+ }
+ else if ("toParam" in object) {
+ result = object.toParam;
+ }
+ else if ("id" in object) {
+ result = object.id;
+ }
+ else {
+ result = object;
+ }
+ return this.is_callable(result) ? result.call(object) : result;
+ }
+ partition_parameters(parts, required_params, default_options, call_arguments) {
+ // eslint-disable-next-line prefer-const
+ let { args, options } = this.extract_options(parts.length, call_arguments);
+ if (args.length > parts.length) {
+ throw new Error("Too many parameters provided for path");
+ }
+ let use_all_parts = args.length > required_params.length;
+ const parts_options = {
+ ...this.configuration.default_url_options,
+ };
+ for (const key in options) {
+ const value = options[key];
+ if (!hasProp(options, key))
+ continue;
+ use_all_parts = true;
+ if (parts.includes(key)) {
+ parts_options[key] = value;
+ }
+ }
+ options = {
+ ...this.configuration.default_url_options,
+ ...default_options,
+ ...options,
+ };
+ const keyword_parameters = {};
+ let query_parameters = {};
+ for (const key in options) {
+ if (!hasProp(options, key))
+ continue;
+ const value = options[key];
+ if (key === "params") {
+ if (this.is_object(value)) {
+ query_parameters = {
+ ...query_parameters,
+ ...value,
+ };
+ }
+ else {
+ throw new Error("params value should always be an object");
+ }
+ }
+ else if (this.is_reserved_option(key)) {
+ keyword_parameters[key] = value;
+ }
+ else {
+ if (!this.is_nullable(value) &&
+ (value !== default_options[key] || required_params.includes(key))) {
+ query_parameters[key] = value;
+ }
+ }
+ }
+ const route_parts = use_all_parts ? parts : required_params;
+ let i = 0;
+ for (const part of route_parts) {
+ if (i < args.length) {
+ const value = args[i];
+ if (!hasProp(parts_options, part)) {
+ query_parameters[part] = value;
+ ++i;
+ }
+ }
+ }
+ return { keyword_parameters, query_parameters };
+ }
+ build_route(parts, required_params, default_options, route, absolute, args) {
+ const { keyword_parameters, query_parameters, } = this.partition_parameters(parts, required_params, default_options, args);
+ const missing_params = required_params.filter((param) => !hasProp(query_parameters, param) ||
+ this.is_nullable(query_parameters[param]));
+ if (missing_params.length) {
+ throw new ParametersMissing(...missing_params);
+ }
+ let result = this.get_prefix() + this.visit(route, query_parameters);
+ if (keyword_parameters.trailing_slash) {
+ result = result.replace(/(.*?)[/]?$/, "$1/");
+ }
+ const url_params = this.serialize(query_parameters);
+ if (url_params.length) {
+ result += "?" + url_params;
+ }
+ result += keyword_parameters.anchor
+ ? "#" + keyword_parameters.anchor
+ : "";
+ if (absolute) {
+ result = this.route_url(keyword_parameters) + result;
+ }
+ return result;
+ }
+ visit(route, parameters, optional = false) {
+ switch (route[0]) {
+ case NodeTypes.GROUP:
+ return this.visit(route[1], parameters, true);
+ case NodeTypes.CAT:
+ return this.visit_cat(route, parameters, optional);
+ case NodeTypes.SYMBOL:
+ return this.visit_symbol(route, parameters, optional);
+ case NodeTypes.STAR:
+ return this.visit_globbing(route[1], parameters, true);
+ case NodeTypes.LITERAL:
+ case NodeTypes.SLASH:
+ case NodeTypes.DOT:
+ return route[1];
+ default:
+ throw new Error("Unknown Rails node type");
+ }
+ }
+ is_not_nullable(object) {
+ return !this.is_nullable(object);
+ }
+ is_nullable(object) {
+ return object === undefined || object === null;
+ }
+ visit_cat(
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ [_type, left, right], parameters, optional) {
+ const left_part = this.visit(left, parameters, optional);
+ let right_part = this.visit(right, parameters, optional);
+ if (optional &&
+ ((this.is_optional_node(left[0]) && !left_part) ||
+ (this.is_optional_node(right[0]) && !right_part))) {
+ return "";
+ }
+ // if left_part ends on '/' and right_part starts on '/'
+ if (left_part[left_part.length - 1] === "/" && right_part[0] === "/") {
+ // strip slash from right_part
+ // to prevent double slash
+ right_part = right_part.substring(1);
+ }
+ return left_part + right_part;
+ }
+ visit_symbol(
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ [_type, key], parameters, optional) {
+ const value = this.path_identifier(parameters[key]);
+ delete parameters[key];
+ if (value.length) {
+ return this.encode_segment(value);
+ }
+ if (optional) {
+ return "";
+ }
+ else {
+ throw new ParametersMissing(key);
+ }
+ }
+ encode_segment(segment) {
+ return segment.replace(UriEncoderSegmentRegex, (str) => encodeURIComponent(str));
+ }
+ is_optional_node(node) {
+ return [NodeTypes.STAR, NodeTypes.SYMBOL, NodeTypes.CAT].includes(node);
+ }
+ build_path_spec(route, wildcard = false) {
+ let key;
+ switch (route[0]) {
+ case NodeTypes.GROUP:
+ return "(" + this.build_path_spec(route[1]) + ")";
+ case NodeTypes.CAT:
+ return (this.build_path_spec(route[1]) + this.build_path_spec(route[2]));
+ case NodeTypes.STAR:
+ return this.build_path_spec(route[1], true);
+ case NodeTypes.SYMBOL:
+ key = route[1];
+ if (wildcard) {
+ return (key.startsWith("*") ? "" : "*") + key;
+ }
+ else {
+ return ":" + key;
+ }
+ break;
+ case NodeTypes.SLASH:
+ case NodeTypes.DOT:
+ case NodeTypes.LITERAL:
+ return route[1];
+ default:
+ throw new Error("Unknown Rails node type");
+ }
+ }
+ visit_globbing(route, parameters, optional) {
+ const key = route[1];
+ let value = parameters[key];
+ delete parameters[key];
+ if (this.is_nullable(value)) {
+ return this.visit(route, parameters, optional);
+ }
+ if (this.is_array(value)) {
+ value = value.join("/");
+ }
+ const result = this.path_identifier(value);
+ return false
+ ? result
+ : encodeURI(result);
+ }
+ get_prefix() {
+ const prefix = this.configuration.prefix;
+ return prefix.match("/$")
+ ? prefix.substring(0, prefix.length - 1)
+ : prefix;
+ }
+ route(parts_table, route_spec, absolute = false) {
+ const required_params = [];
+ const parts = [];
+ const default_options = {};
+ for (const [part, { r: required, d: value }] of Object.entries(parts_table)) {
+ parts.push(part);
+ if (required) {
+ required_params.push(part);
+ }
+ if (this.is_not_nullable(value)) {
+ default_options[part] = value;
+ }
+ }
+ const result = (...args) => {
+ return this.build_route(parts, required_params, default_options, route_spec, absolute, args);
+ };
+ result.requiredParams = () => required_params;
+ result.toString = () => {
+ return this.build_path_spec(route_spec);
+ };
+ return result;
+ }
+ route_url(route_defaults) {
+ const hostname = route_defaults.host || this.current_host();
+ if (!hostname) {
+ return "";
+ }
+ const subdomain = route_defaults.subdomain
+ ? route_defaults.subdomain + "."
+ : "";
+ const protocol = route_defaults.protocol || this.current_protocol();
+ let port = route_defaults.port ||
+ (!route_defaults.host ? this.current_port() : undefined);
+ port = port ? ":" + port : "";
+ return protocol + "://" + subdomain + hostname + port;
+ }
+ current_host() {
+ var _a;
+ return (isBrowser && ((_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.hostname)) || "";
+ }
+ current_protocol() {
+ var _a, _b;
+ return ((isBrowser && ((_b = (_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.protocol) === null || _b === void 0 ? void 0 : _b.replace(/:$/, ""))) || "http");
+ }
+ current_port() {
+ var _a;
+ return (isBrowser && ((_a = window === null || window === void 0 ? void 0 : window.location) === null || _a === void 0 ? void 0 : _a.port)) || "";
+ }
+ is_object(value) {
+ return (typeof value === "object" &&
+ Object.prototype.toString.call(value) === "[object Object]");
+ }
+ is_array(object) {
+ return object instanceof Array;
+ }
+ is_callable(object) {
+ return typeof object === "function" && !!object.call;
+ }
+ is_reserved_option(key) {
+ return ReservedOptions.includes(key);
+ }
+ configure(new_config) {
+ this.configuration = { ...this.configuration, ...new_config };
+ return this.configuration;
+ }
+ config() {
+ return { ...this.configuration };
+ }
+ is_module_supported(name) {
+ return ModuleReferences[name].isSupported();
+ }
+ ensure_module_supported(name) {
+ if (!this.is_module_supported(name)) {
+ throw new Error(`${name} is not supported by runtime`);
+ }
+ }
+ define_module(name, module) {
+ this.ensure_module_supported(name);
+ ModuleReferences[name].define(module);
+ }
}
- }
- const Utils = new UtilsClass();
- // We want this helper name to be short
- const __jsr = {
- r(parts_table, route_spec, absolute) {
- return Utils.route(parts_table, route_spec, absolute);
- },
- };
- const result = {
- ...__jsr,
- configure: (config) => {
- return Utils.configure(config);
- },
- config: () => {
- return Utils.config();
- },
- serialize: (object) => {
- return Utils.serialize(object);
- },
- ...{},
- };
- Utils.define_module("ESM", result);
- return result;
+ const Utils = new UtilsClass();
+ // We want this helper name to be short
+ const __jsr = {
+ r(parts_table, route_spec, absolute) {
+ return Utils.route(parts_table, route_spec, absolute);
+ },
+ };
+ const result = {
+ ...__jsr,
+ configure: (config) => {
+ return Utils.configure(config);
+ },
+ config: () => {
+ return Utils.config();
+ },
+ serialize: (object) => {
+ return Utils.serialize(object);
+ },
+ ...{},
+ };
+ Utils.define_module("ESM", result);
+ return result;
})();
export const configure = __jsr.configure;
@@ -511,7 +511,7 @@ export const serialize = __jsr.serialize;
* @param {object | undefined} options
* @returns {string} route path
*/
-export const adminUserPath = __jsr.r({ "id": { "r": true }, "format": {} }, [2, [7, "/"], [2, [6, "admin"], [2, [7, "/"], [2, [6, "users"], [2, [7, "/"], [2, [3, "id"], [1, [2, [8, "."], [3, "format"]]]]]]]]]);
+export const adminUserPath = __jsr.r({"id":{"r":true},"format":{}}, [2,[7,"/"],[2,[6,"admin"],[2,[7,"/"],[2,[6,"users"],[2,[7,"/"],[2,[3,"id"],[1,[2,[8,"."],[3,"format"]]]]]]]]]);
/**
* Generates rails route to
@@ -519,7 +519,7 @@ export const adminUserPath = __jsr.r({ "id": { "r": true }, "format": {} }, [2,
* @param {object | undefined} options
* @returns {string} route path
*/
-export const adminUsersPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "admin"], [2, [7, "/"], [2, [6, "users"], [1, [2, [8, "."], [3, "format"]]]]]]]);
+export const adminUsersPath = __jsr.r({"format":{}}, [2,[7,"/"],[2,[6,"admin"],[2,[7,"/"],[2,[6,"users"],[1,[2,[8,"."],[3,"format"]]]]]]]);
/**
* Generates rails route to
@@ -528,7 +528,7 @@ export const adminUsersPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "a
* @param {object | undefined} options
* @returns {string} route path
*/
-export const apiV1TaskPath = __jsr.r({ "id": { "r": true }, "format": { "d": "json" } }, [2, [7, "/"], [2, [6, "api"], [2, [7, "/"], [2, [6, "v1"], [2, [7, "/"], [2, [6, "tasks"], [2, [7, "/"], [2, [3, "id"], [1, [2, [8, "."], [3, "format"]]]]]]]]]]]);
+export const apiV1TaskPath = __jsr.r({"id":{"r":true},"format":{"d":"json"}}, [2,[7,"/"],[2,[6,"api"],[2,[7,"/"],[2,[6,"v1"],[2,[7,"/"],[2,[6,"tasks"],[2,[7,"/"],[2,[3,"id"],[1,[2,[8,"."],[3,"format"]]]]]]]]]]]);
/**
* Generates rails route to
@@ -536,7 +536,7 @@ export const apiV1TaskPath = __jsr.r({ "id": { "r": true }, "format": { "d": "js
* @param {object | undefined} options
* @returns {string} route path
*/
-export const apiV1TasksPath = __jsr.r({ "format": { "d": "json" } }, [2, [7, "/"], [2, [6, "api"], [2, [7, "/"], [2, [6, "v1"], [2, [7, "/"], [2, [6, "tasks"], [1, [2, [8, "."], [3, "format"]]]]]]]]]);
+export const apiV1TasksPath = __jsr.r({"format":{"d":"json"}}, [2,[7,"/"],[2,[6,"api"],[2,[7,"/"],[2,[6,"v1"],[2,[7,"/"],[2,[6,"tasks"],[1,[2,[8,"."],[3,"format"]]]]]]]]]);
/**
* Generates rails route to
@@ -545,7 +545,7 @@ export const apiV1TasksPath = __jsr.r({ "format": { "d": "json" } }, [2, [7, "/"
* @param {object | undefined} options
* @returns {string} route path
*/
-export const apiV1UserPath = __jsr.r({ "id": { "r": true }, "format": {} }, [2, [7, "/"], [2, [6, "api"], [2, [7, "/"], [2, [6, "v1"], [2, [7, "/"], [2, [6, "users"], [2, [7, "/"], [2, [3, "id"], [1, [2, [8, "."], [3, "format"]]]]]]]]]]]);
+export const apiV1UserPath = __jsr.r({"id":{"r":true},"format":{"d":"json"}}, [2,[7,"/"],[2,[6,"api"],[2,[7,"/"],[2,[6,"v1"],[2,[7,"/"],[2,[6,"users"],[2,[7,"/"],[2,[3,"id"],[1,[2,[8,"."],[3,"format"]]]]]]]]]]]);
/**
* Generates rails route to
@@ -553,7 +553,16 @@ export const apiV1UserPath = __jsr.r({ "id": { "r": true }, "format": {} }, [2,
* @param {object | undefined} options
* @returns {string} route path
*/
-export const apiV1UsersPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "api"], [2, [7, "/"], [2, [6, "v1"], [2, [7, "/"], [2, [6, "users"], [1, [2, [8, "."], [3, "format"]]]]]]]]]);
+export const apiV1UsersPath = __jsr.r({"format":{"d":"json"}}, [2,[7,"/"],[2,[6,"api"],[2,[7,"/"],[2,[6,"v1"],[2,[7,"/"],[2,[6,"users"],[1,[2,[8,"."],[3,"format"]]]]]]]]]);
+
+/**
+ * Generates rails route to
+ * /api/v1/tasks/:id/attach_image(.:format)
+ * @param {any} id
+ * @param {object | undefined} options
+ * @returns {string} route path
+ */
+export const attachImageApiV1TaskPath = __jsr.r({"id":{"r":true},"format":{"d":"json"}}, [2,[7,"/"],[2,[6,"api"],[2,[7,"/"],[2,[6,"v1"],[2,[7,"/"],[2,[6,"tasks"],[2,[7,"/"],[2,[3,"id"],[2,[7,"/"],[2,[6,"attach_image"],[1,[2,[8,"."],[3,"format"]]]]]]]]]]]]]);
/**
* Generates rails route to
@@ -561,7 +570,7 @@ export const apiV1UsersPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "a
* @param {object | undefined} options
* @returns {string} route path
*/
-export const boardPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "board"], [1, [2, [8, "."], [3, "format"]]]]]);
+export const boardPath = __jsr.r({"format":{}}, [2,[7,"/"],[2,[6,"board"],[1,[2,[8,"."],[3,"format"]]]]]);
/**
* Generates rails route to
@@ -569,7 +578,7 @@ export const boardPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "board"
* @param {object | undefined} options
* @returns {string} route path
*/
-export const developersPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "developers"], [1, [2, [8, "."], [3, "format"]]]]]);
+export const developersPath = __jsr.r({"format":{}}, [2,[7,"/"],[2,[6,"developers"],[1,[2,[8,"."],[3,"format"]]]]]);
/**
* Generates rails route to
@@ -578,7 +587,15 @@ export const developersPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "d
* @param {object | undefined} options
* @returns {string} route path
*/
-export const editAdminUserPath = __jsr.r({ "id": { "r": true }, "format": {} }, [2, [7, "/"], [2, [6, "admin"], [2, [7, "/"], [2, [6, "users"], [2, [7, "/"], [2, [3, "id"], [2, [7, "/"], [2, [6, "edit"], [1, [2, [8, "."], [3, "format"]]]]]]]]]]]);
+export const editAdminUserPath = __jsr.r({"id":{"r":true},"format":{}}, [2,[7,"/"],[2,[6,"admin"],[2,[7,"/"],[2,[6,"users"],[2,[7,"/"],[2,[3,"id"],[2,[7,"/"],[2,[6,"edit"],[1,[2,[8,"."],[3,"format"]]]]]]]]]]]);
+
+/**
+ * Generates rails route to
+ * /password_resets/edit(.:format)
+ * @param {object | undefined} options
+ * @returns {string} route path
+ */
+export const editPasswordResetsPath = __jsr.r({"format":{}}, [2,[7,"/"],[2,[6,"password_resets"],[2,[7,"/"],[2,[6,"edit"],[1,[2,[8,"."],[3,"format"]]]]]]]);
/**
* Generates rails route to
@@ -587,7 +604,49 @@ export const editAdminUserPath = __jsr.r({ "id": { "r": true }, "format": {} },
* @param {object | undefined} options
* @returns {string} route path
*/
-export const editRailsConductorInboundEmailPath = __jsr.r({ "id": { "r": true }, "format": {} }, [2, [7, "/"], [2, [6, "rails"], [2, [7, "/"], [2, [6, "conductor"], [2, [7, "/"], [2, [6, "action_mailbox"], [2, [7, "/"], [2, [6, "inbound_emails"], [2, [7, "/"], [2, [3, "id"], [2, [7, "/"], [2, [6, "edit"], [1, [2, [8, "."], [3, "format"]]]]]]]]]]]]]]]);
+export const editRailsConductorInboundEmailPath = __jsr.r({"id":{"r":true},"format":{}}, [2,[7,"/"],[2,[6,"rails"],[2,[7,"/"],[2,[6,"conductor"],[2,[7,"/"],[2,[6,"action_mailbox"],[2,[7,"/"],[2,[6,"inbound_emails"],[2,[7,"/"],[2,[3,"id"],[2,[7,"/"],[2,[6,"edit"],[1,[2,[8,"."],[3,"format"]]]]]]]]]]]]]]]);
+
+/**
+ * Generates rails route to
+ * /letter_opener
+ * @param {object | undefined} options
+ * @returns {string} route path
+ */
+export const letterOpenerWebPath = __jsr.r({}, [2,[7,"/"],[6,"letter_opener"]]);
+
+/**
+ * Generates rails route to
+ * /letter_opener/
+ * @param {object | undefined} options
+ * @returns {string} route path
+ */
+export const letterOpenerWebLettersPath = __jsr.r({}, [2,[2,[7,"/"],[6,"letter_opener"]],[7,"/"]]);
+
+/**
+ * Generates rails route to
+ * /letter_opener/clear(.:format)
+ * @param {object | undefined} options
+ * @returns {string} route path
+ */
+export const letterOpenerWebClearLettersPath = __jsr.r({"format":{}}, [2,[2,[2,[7,"/"],[6,"letter_opener"]],[7,"/"]],[2,[6,"clear"],[1,[2,[8,"."],[3,"format"]]]]]);
+
+/**
+ * Generates rails route to
+ * /letter_opener/:id(/:style)(.:format)
+ * @param {any} id
+ * @param {object | undefined} options
+ * @returns {string} route path
+ */
+export const letterOpenerWebLetterPath = __jsr.r({"id":{"r":true},"style":{},"format":{}}, [2,[2,[2,[7,"/"],[6,"letter_opener"]],[7,"/"]],[2,[3,"id"],[2,[1,[2,[7,"/"],[3,"style"]]],[1,[2,[8,"."],[3,"format"]]]]]]);
+
+/**
+ * Generates rails route to
+ * /letter_opener/:id/delete(.:format)
+ * @param {any} id
+ * @param {object | undefined} options
+ * @returns {string} route path
+ */
+export const letterOpenerWebDeleteLetterPath = __jsr.r({"id":{"r":true},"format":{}}, [2,[2,[2,[7,"/"],[6,"letter_opener"]],[7,"/"]],[2,[3,"id"],[2,[7,"/"],[2,[6,"delete"],[1,[2,[8,"."],[3,"format"]]]]]]]);
/**
* Generates rails route to
@@ -595,7 +654,7 @@ export const editRailsConductorInboundEmailPath = __jsr.r({ "id": { "r": true },
* @param {object | undefined} options
* @returns {string} route path
*/
-export const newAdminUserPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "admin"], [2, [7, "/"], [2, [6, "users"], [2, [7, "/"], [2, [6, "new"], [1, [2, [8, "."], [3, "format"]]]]]]]]]);
+export const newAdminUserPath = __jsr.r({"format":{}}, [2,[7,"/"],[2,[6,"admin"],[2,[7,"/"],[2,[6,"users"],[2,[7,"/"],[2,[6,"new"],[1,[2,[8,"."],[3,"format"]]]]]]]]]);
/**
* Generates rails route to
@@ -603,7 +662,15 @@ export const newAdminUserPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6,
* @param {object | undefined} options
* @returns {string} route path
*/
-export const newDeveloperPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "developers"], [2, [7, "/"], [2, [6, "new"], [1, [2, [8, "."], [3, "format"]]]]]]]);
+export const newDeveloperPath = __jsr.r({"format":{}}, [2,[7,"/"],[2,[6,"developers"],[2,[7,"/"],[2,[6,"new"],[1,[2,[8,"."],[3,"format"]]]]]]]);
+
+/**
+ * Generates rails route to
+ * /password_resets/new(.:format)
+ * @param {object | undefined} options
+ * @returns {string} route path
+ */
+export const newPasswordResetsPath = __jsr.r({"format":{}}, [2,[7,"/"],[2,[6,"password_resets"],[2,[7,"/"],[2,[6,"new"],[1,[2,[8,"."],[3,"format"]]]]]]]);
/**
* Generates rails route to
@@ -611,7 +678,7 @@ export const newDeveloperPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6,
* @param {object | undefined} options
* @returns {string} route path
*/
-export const newRailsConductorInboundEmailPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "rails"], [2, [7, "/"], [2, [6, "conductor"], [2, [7, "/"], [2, [6, "action_mailbox"], [2, [7, "/"], [2, [6, "inbound_emails"], [2, [7, "/"], [2, [6, "new"], [1, [2, [8, "."], [3, "format"]]]]]]]]]]]]]);
+export const newRailsConductorInboundEmailPath = __jsr.r({"format":{}}, [2,[7,"/"],[2,[6,"rails"],[2,[7,"/"],[2,[6,"conductor"],[2,[7,"/"],[2,[6,"action_mailbox"],[2,[7,"/"],[2,[6,"inbound_emails"],[2,[7,"/"],[2,[6,"new"],[1,[2,[8,"."],[3,"format"]]]]]]]]]]]]]);
/**
* Generates rails route to
@@ -619,7 +686,15 @@ export const newRailsConductorInboundEmailPath = __jsr.r({ "format": {} }, [2, [
* @param {object | undefined} options
* @returns {string} route path
*/
-export const newSessionPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "session"], [2, [7, "/"], [2, [6, "new"], [1, [2, [8, "."], [3, "format"]]]]]]]);
+export const newSessionPath = __jsr.r({"format":{}}, [2,[7,"/"],[2,[6,"session"],[2,[7,"/"],[2,[6,"new"],[1,[2,[8,"."],[3,"format"]]]]]]]);
+
+/**
+ * Generates rails route to
+ * /password_resets(.:format)
+ * @param {object | undefined} options
+ * @returns {string} route path
+ */
+export const passwordResetsPath = __jsr.r({"format":{}}, [2,[7,"/"],[2,[6,"password_resets"],[1,[2,[8,"."],[3,"format"]]]]]);
/**
* Generates rails route to
@@ -630,7 +705,7 @@ export const newSessionPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "s
* @param {object | undefined} options
* @returns {string} route path
*/
-export const railsBlobRepresentationPath = __jsr.r({ "signed_blob_id": { "r": true }, "variation_key": { "r": true }, "filename": { "r": true }, "format": {} }, [2, [7, "/"], [2, [6, "rails"], [2, [7, "/"], [2, [6, "active_storage"], [2, [7, "/"], [2, [6, "representations"], [2, [7, "/"], [2, [3, "signed_blob_id"], [2, [7, "/"], [2, [3, "variation_key"], [2, [7, "/"], [2, [5, [3, "filename"]], [1, [2, [8, "."], [3, "format"]]]]]]]]]]]]]]]);
+export const railsBlobRepresentationPath = __jsr.r({"signed_blob_id":{"r":true},"variation_key":{"r":true},"filename":{"r":true},"format":{}}, [2,[7,"/"],[2,[6,"rails"],[2,[7,"/"],[2,[6,"active_storage"],[2,[7,"/"],[2,[6,"representations"],[2,[7,"/"],[2,[3,"signed_blob_id"],[2,[7,"/"],[2,[3,"variation_key"],[2,[7,"/"],[2,[5,[3,"filename"]],[1,[2,[8,"."],[3,"format"]]]]]]]]]]]]]]]);
/**
* Generates rails route to
@@ -639,7 +714,7 @@ export const railsBlobRepresentationPath = __jsr.r({ "signed_blob_id": { "r": tr
* @param {object | undefined} options
* @returns {string} route path
*/
-export const railsConductorInboundEmailPath = __jsr.r({ "id": { "r": true }, "format": {} }, [2, [7, "/"], [2, [6, "rails"], [2, [7, "/"], [2, [6, "conductor"], [2, [7, "/"], [2, [6, "action_mailbox"], [2, [7, "/"], [2, [6, "inbound_emails"], [2, [7, "/"], [2, [3, "id"], [1, [2, [8, "."], [3, "format"]]]]]]]]]]]]]);
+export const railsConductorInboundEmailPath = __jsr.r({"id":{"r":true},"format":{}}, [2,[7,"/"],[2,[6,"rails"],[2,[7,"/"],[2,[6,"conductor"],[2,[7,"/"],[2,[6,"action_mailbox"],[2,[7,"/"],[2,[6,"inbound_emails"],[2,[7,"/"],[2,[3,"id"],[1,[2,[8,"."],[3,"format"]]]]]]]]]]]]]);
/**
* Generates rails route to
@@ -648,7 +723,7 @@ export const railsConductorInboundEmailPath = __jsr.r({ "id": { "r": true }, "fo
* @param {object | undefined} options
* @returns {string} route path
*/
-export const railsConductorInboundEmailReroutePath = __jsr.r({ "inbound_email_id": { "r": true }, "format": {} }, [2, [7, "/"], [2, [6, "rails"], [2, [7, "/"], [2, [6, "conductor"], [2, [7, "/"], [2, [6, "action_mailbox"], [2, [7, "/"], [2, [3, "inbound_email_id"], [2, [7, "/"], [2, [6, "reroute"], [1, [2, [8, "."], [3, "format"]]]]]]]]]]]]]);
+export const railsConductorInboundEmailReroutePath = __jsr.r({"inbound_email_id":{"r":true},"format":{}}, [2,[7,"/"],[2,[6,"rails"],[2,[7,"/"],[2,[6,"conductor"],[2,[7,"/"],[2,[6,"action_mailbox"],[2,[7,"/"],[2,[3,"inbound_email_id"],[2,[7,"/"],[2,[6,"reroute"],[1,[2,[8,"."],[3,"format"]]]]]]]]]]]]]);
/**
* Generates rails route to
@@ -656,7 +731,7 @@ export const railsConductorInboundEmailReroutePath = __jsr.r({ "inbound_email_id
* @param {object | undefined} options
* @returns {string} route path
*/
-export const railsConductorInboundEmailsPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "rails"], [2, [7, "/"], [2, [6, "conductor"], [2, [7, "/"], [2, [6, "action_mailbox"], [2, [7, "/"], [2, [6, "inbound_emails"], [1, [2, [8, "."], [3, "format"]]]]]]]]]]]);
+export const railsConductorInboundEmailsPath = __jsr.r({"format":{}}, [2,[7,"/"],[2,[6,"rails"],[2,[7,"/"],[2,[6,"conductor"],[2,[7,"/"],[2,[6,"action_mailbox"],[2,[7,"/"],[2,[6,"inbound_emails"],[1,[2,[8,"."],[3,"format"]]]]]]]]]]]);
/**
* Generates rails route to
@@ -664,7 +739,7 @@ export const railsConductorInboundEmailsPath = __jsr.r({ "format": {} }, [2, [7,
* @param {object | undefined} options
* @returns {string} route path
*/
-export const railsDirectUploadsPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "rails"], [2, [7, "/"], [2, [6, "active_storage"], [2, [7, "/"], [2, [6, "direct_uploads"], [1, [2, [8, "."], [3, "format"]]]]]]]]]);
+export const railsDirectUploadsPath = __jsr.r({"format":{}}, [2,[7,"/"],[2,[6,"rails"],[2,[7,"/"],[2,[6,"active_storage"],[2,[7,"/"],[2,[6,"direct_uploads"],[1,[2,[8,"."],[3,"format"]]]]]]]]]);
/**
* Generates rails route to
@@ -674,7 +749,7 @@ export const railsDirectUploadsPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2
* @param {object | undefined} options
* @returns {string} route path
*/
-export const railsDiskServicePath = __jsr.r({ "encoded_key": { "r": true }, "filename": { "r": true }, "format": {} }, [2, [7, "/"], [2, [6, "rails"], [2, [7, "/"], [2, [6, "active_storage"], [2, [7, "/"], [2, [6, "disk"], [2, [7, "/"], [2, [3, "encoded_key"], [2, [7, "/"], [2, [5, [3, "filename"]], [1, [2, [8, "."], [3, "format"]]]]]]]]]]]]]);
+export const railsDiskServicePath = __jsr.r({"encoded_key":{"r":true},"filename":{"r":true},"format":{}}, [2,[7,"/"],[2,[6,"rails"],[2,[7,"/"],[2,[6,"active_storage"],[2,[7,"/"],[2,[6,"disk"],[2,[7,"/"],[2,[3,"encoded_key"],[2,[7,"/"],[2,[5,[3,"filename"]],[1,[2,[8,"."],[3,"format"]]]]]]]]]]]]]);
/**
* Generates rails route to
@@ -682,7 +757,7 @@ export const railsDiskServicePath = __jsr.r({ "encoded_key": { "r": true }, "fil
* @param {object | undefined} options
* @returns {string} route path
*/
-export const railsInfoPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "rails"], [2, [7, "/"], [2, [6, "info"], [1, [2, [8, "."], [3, "format"]]]]]]]);
+export const railsInfoPath = __jsr.r({"format":{}}, [2,[7,"/"],[2,[6,"rails"],[2,[7,"/"],[2,[6,"info"],[1,[2,[8,"."],[3,"format"]]]]]]]);
/**
* Generates rails route to
@@ -690,7 +765,7 @@ export const railsInfoPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "ra
* @param {object | undefined} options
* @returns {string} route path
*/
-export const railsInfoPropertiesPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "rails"], [2, [7, "/"], [2, [6, "info"], [2, [7, "/"], [2, [6, "properties"], [1, [2, [8, "."], [3, "format"]]]]]]]]]);
+export const railsInfoPropertiesPath = __jsr.r({"format":{}}, [2,[7,"/"],[2,[6,"rails"],[2,[7,"/"],[2,[6,"info"],[2,[7,"/"],[2,[6,"properties"],[1,[2,[8,"."],[3,"format"]]]]]]]]]);
/**
* Generates rails route to
@@ -698,7 +773,7 @@ export const railsInfoPropertiesPath = __jsr.r({ "format": {} }, [2, [7, "/"], [
* @param {object | undefined} options
* @returns {string} route path
*/
-export const railsInfoRoutesPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "rails"], [2, [7, "/"], [2, [6, "info"], [2, [7, "/"], [2, [6, "routes"], [1, [2, [8, "."], [3, "format"]]]]]]]]]);
+export const railsInfoRoutesPath = __jsr.r({"format":{}}, [2,[7,"/"],[2,[6,"rails"],[2,[7,"/"],[2,[6,"info"],[2,[7,"/"],[2,[6,"routes"],[1,[2,[8,"."],[3,"format"]]]]]]]]]);
/**
* Generates rails route to
@@ -706,7 +781,7 @@ export const railsInfoRoutesPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [
* @param {object | undefined} options
* @returns {string} route path
*/
-export const railsMailersPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "rails"], [2, [7, "/"], [2, [6, "mailers"], [1, [2, [8, "."], [3, "format"]]]]]]]);
+export const railsMailersPath = __jsr.r({"format":{}}, [2,[7,"/"],[2,[6,"rails"],[2,[7,"/"],[2,[6,"mailers"],[1,[2,[8,"."],[3,"format"]]]]]]]);
/**
* Generates rails route to
@@ -714,7 +789,7 @@ export const railsMailersPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6,
* @param {object | undefined} options
* @returns {string} route path
*/
-export const railsMailgunInboundEmailsPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "rails"], [2, [7, "/"], [2, [6, "action_mailbox"], [2, [7, "/"], [2, [6, "mailgun"], [2, [7, "/"], [2, [6, "inbound_emails"], [2, [7, "/"], [2, [6, "mime"], [1, [2, [8, "."], [3, "format"]]]]]]]]]]]]]);
+export const railsMailgunInboundEmailsPath = __jsr.r({"format":{}}, [2,[7,"/"],[2,[6,"rails"],[2,[7,"/"],[2,[6,"action_mailbox"],[2,[7,"/"],[2,[6,"mailgun"],[2,[7,"/"],[2,[6,"inbound_emails"],[2,[7,"/"],[2,[6,"mime"],[1,[2,[8,"."],[3,"format"]]]]]]]]]]]]]);
/**
* Generates rails route to
@@ -722,7 +797,7 @@ export const railsMailgunInboundEmailsPath = __jsr.r({ "format": {} }, [2, [7, "
* @param {object | undefined} options
* @returns {string} route path
*/
-export const railsMandrillInboundEmailsPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "rails"], [2, [7, "/"], [2, [6, "action_mailbox"], [2, [7, "/"], [2, [6, "mandrill"], [2, [7, "/"], [2, [6, "inbound_emails"], [1, [2, [8, "."], [3, "format"]]]]]]]]]]]);
+export const railsMandrillInboundEmailsPath = __jsr.r({"format":{}}, [2,[7,"/"],[2,[6,"rails"],[2,[7,"/"],[2,[6,"action_mailbox"],[2,[7,"/"],[2,[6,"mandrill"],[2,[7,"/"],[2,[6,"inbound_emails"],[1,[2,[8,"."],[3,"format"]]]]]]]]]]]);
/**
* Generates rails route to
@@ -730,7 +805,7 @@ export const railsMandrillInboundEmailsPath = __jsr.r({ "format": {} }, [2, [7,
* @param {object | undefined} options
* @returns {string} route path
*/
-export const railsMandrillInboundHealthCheckPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "rails"], [2, [7, "/"], [2, [6, "action_mailbox"], [2, [7, "/"], [2, [6, "mandrill"], [2, [7, "/"], [2, [6, "inbound_emails"], [1, [2, [8, "."], [3, "format"]]]]]]]]]]]);
+export const railsMandrillInboundHealthCheckPath = __jsr.r({"format":{}}, [2,[7,"/"],[2,[6,"rails"],[2,[7,"/"],[2,[6,"action_mailbox"],[2,[7,"/"],[2,[6,"mandrill"],[2,[7,"/"],[2,[6,"inbound_emails"],[1,[2,[8,"."],[3,"format"]]]]]]]]]]]);
/**
* Generates rails route to
@@ -738,7 +813,7 @@ export const railsMandrillInboundHealthCheckPath = __jsr.r({ "format": {} }, [2,
* @param {object | undefined} options
* @returns {string} route path
*/
-export const railsPostmarkInboundEmailsPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "rails"], [2, [7, "/"], [2, [6, "action_mailbox"], [2, [7, "/"], [2, [6, "postmark"], [2, [7, "/"], [2, [6, "inbound_emails"], [1, [2, [8, "."], [3, "format"]]]]]]]]]]]);
+export const railsPostmarkInboundEmailsPath = __jsr.r({"format":{}}, [2,[7,"/"],[2,[6,"rails"],[2,[7,"/"],[2,[6,"action_mailbox"],[2,[7,"/"],[2,[6,"postmark"],[2,[7,"/"],[2,[6,"inbound_emails"],[1,[2,[8,"."],[3,"format"]]]]]]]]]]]);
/**
* Generates rails route to
@@ -746,7 +821,7 @@ export const railsPostmarkInboundEmailsPath = __jsr.r({ "format": {} }, [2, [7,
* @param {object | undefined} options
* @returns {string} route path
*/
-export const railsRelayInboundEmailsPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "rails"], [2, [7, "/"], [2, [6, "action_mailbox"], [2, [7, "/"], [2, [6, "relay"], [2, [7, "/"], [2, [6, "inbound_emails"], [1, [2, [8, "."], [3, "format"]]]]]]]]]]]);
+export const railsRelayInboundEmailsPath = __jsr.r({"format":{}}, [2,[7,"/"],[2,[6,"rails"],[2,[7,"/"],[2,[6,"action_mailbox"],[2,[7,"/"],[2,[6,"relay"],[2,[7,"/"],[2,[6,"inbound_emails"],[1,[2,[8,"."],[3,"format"]]]]]]]]]]]);
/**
* Generates rails route to
@@ -754,7 +829,7 @@ export const railsRelayInboundEmailsPath = __jsr.r({ "format": {} }, [2, [7, "/"
* @param {object | undefined} options
* @returns {string} route path
*/
-export const railsSendgridInboundEmailsPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "rails"], [2, [7, "/"], [2, [6, "action_mailbox"], [2, [7, "/"], [2, [6, "sendgrid"], [2, [7, "/"], [2, [6, "inbound_emails"], [1, [2, [8, "."], [3, "format"]]]]]]]]]]]);
+export const railsSendgridInboundEmailsPath = __jsr.r({"format":{}}, [2,[7,"/"],[2,[6,"rails"],[2,[7,"/"],[2,[6,"action_mailbox"],[2,[7,"/"],[2,[6,"sendgrid"],[2,[7,"/"],[2,[6,"inbound_emails"],[1,[2,[8,"."],[3,"format"]]]]]]]]]]]);
/**
* Generates rails route to
@@ -764,7 +839,16 @@ export const railsSendgridInboundEmailsPath = __jsr.r({ "format": {} }, [2, [7,
* @param {object | undefined} options
* @returns {string} route path
*/
-export const railsServiceBlobPath = __jsr.r({ "signed_id": { "r": true }, "filename": { "r": true }, "format": {} }, [2, [7, "/"], [2, [6, "rails"], [2, [7, "/"], [2, [6, "active_storage"], [2, [7, "/"], [2, [6, "blobs"], [2, [7, "/"], [2, [3, "signed_id"], [2, [7, "/"], [2, [5, [3, "filename"]], [1, [2, [8, "."], [3, "format"]]]]]]]]]]]]]);
+export const railsServiceBlobPath = __jsr.r({"signed_id":{"r":true},"filename":{"r":true},"format":{}}, [2,[7,"/"],[2,[6,"rails"],[2,[7,"/"],[2,[6,"active_storage"],[2,[7,"/"],[2,[6,"blobs"],[2,[7,"/"],[2,[3,"signed_id"],[2,[7,"/"],[2,[5,[3,"filename"]],[1,[2,[8,"."],[3,"format"]]]]]]]]]]]]]);
+
+/**
+ * Generates rails route to
+ * /api/v1/tasks/:id/remove_image(.:format)
+ * @param {any} id
+ * @param {object | undefined} options
+ * @returns {string} route path
+ */
+export const removeImageApiV1TaskPath = __jsr.r({"id":{"r":true},"format":{"d":"json"}}, [2,[7,"/"],[2,[6,"api"],[2,[7,"/"],[2,[6,"v1"],[2,[7,"/"],[2,[6,"tasks"],[2,[7,"/"],[2,[3,"id"],[2,[7,"/"],[2,[6,"remove_image"],[1,[2,[8,"."],[3,"format"]]]]]]]]]]]]]);
/**
* Generates rails route to
@@ -772,7 +856,7 @@ export const railsServiceBlobPath = __jsr.r({ "signed_id": { "r": true }, "filen
* @param {object | undefined} options
* @returns {string} route path
*/
-export const rootPath = __jsr.r({}, [7, "/"]);
+export const rootPath = __jsr.r({}, [7,"/"]);
/**
* Generates rails route to
@@ -780,7 +864,15 @@ export const rootPath = __jsr.r({}, [7, "/"]);
* @param {object | undefined} options
* @returns {string} route path
*/
-export const sessionPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "session"], [1, [2, [8, "."], [3, "format"]]]]]);
+export const sessionPath = __jsr.r({"format":{}}, [2,[7,"/"],[2,[6,"session"],[1,[2,[8,"."],[3,"format"]]]]]);
+
+/**
+ * Generates rails route to
+ * /admin/sidekiq
+ * @param {object | undefined} options
+ * @returns {string} route path
+ */
+export const sidekiqWebPath = __jsr.r({}, [2,[7,"/"],[2,[6,"admin"],[2,[7,"/"],[6,"sidekiq"]]]]);
/**
* Generates rails route to
@@ -789,5 +881,5 @@ export const sessionPath = __jsr.r({ "format": {} }, [2, [7, "/"], [2, [6, "sess
* @param {object | undefined} options
* @returns {string} route path
*/
-export const updateRailsDiskServicePath = __jsr.r({ "encoded_token": { "r": true }, "format": {} }, [2, [7, "/"], [2, [6, "rails"], [2, [7, "/"], [2, [6, "active_storage"], [2, [7, "/"], [2, [6, "disk"], [2, [7, "/"], [2, [3, "encoded_token"], [1, [2, [8, "."], [3, "format"]]]]]]]]]]]);
+export const updateRailsDiskServicePath = __jsr.r({"encoded_token":{"r":true},"format":{}}, [2,[7,"/"],[2,[6,"rails"],[2,[7,"/"],[2,[6,"active_storage"],[2,[7,"/"],[2,[6,"disk"],[2,[7,"/"],[2,[3,"encoded_token"],[1,[2,[8,"."],[3,"format"]]]]]]]]]]]);
diff --git a/app/javascript/utils/fetchHelper.js b/app/javascript/utils/fetchHelper.js
index 537f9b0..baa6334 100644
--- a/app/javascript/utils/fetchHelper.js
+++ b/app/javascript/utils/fetchHelper.js
@@ -1,5 +1,6 @@
import axios from 'axios';
import qs from 'qs';
+import { objectToFormData } from 'object-to-formdata';
import { camelize, decamelize } from './keysConverter';
@@ -64,4 +65,18 @@ export default {
return axios.delete(url, body).then(camelize);
},
+
+ putFormData(url, json) {
+ const body = decamelize(json);
+ body.attachment.image = json.attachment.image;
+ const formData = objectToFormData(body);
+
+ return axios
+ .put(url, formData, {
+ headers: {
+ 'Content-Type': 'multipart/form-data',
+ },
+ })
+ .then(camelize);
+ },
};
diff --git a/app/services/attachment_service.rb b/app/services/attachments_service.rb
similarity index 100%
rename from app/services/attachment_service.rb
rename to app/services/attachments_service.rb
diff --git a/config/environments/development.rb b/config/environments/development.rb
index ce46256..09b7254 100644
--- a/config/environments/development.rb
+++ b/config/environments/development.rb
@@ -60,6 +60,7 @@
# Use an evented file watcher to asynchronously detect changes in source code,
# routes, locales, etc. This feature depends on the listen gem.
+ routes.default_url_options[:host] = 'localhost:3330'
config.file_watcher = ActiveSupport::EventedFileUpdateChecker
config.hosts << '.app.uffizzi.com'
end
diff --git a/package.json b/package.json
index c63ffb3..192ba14 100644
--- a/package.json
+++ b/package.json
@@ -28,12 +28,14 @@
"eslint-plugin-react-hooks": "^4.6.0",
"humps": "^2.0.1",
"material-design-lite": "^1.3.0",
+ "object-to-formdata": "3.0.9",
"prettier": "^2.8.0",
"prop-types": "^15.8.1",
"qs": "^6.11.0",
"ramda": "^0.28.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
+ "react-image-crop": "8.6.4",
"react-redux": "^8.0.5",
"react-select": "^5.7.0",
"redux": "^4.2.0",
@@ -44,4 +46,4 @@
"devDependencies": {
"webpack-dev-server": "^4.11.1"
}
-}
+}
\ No newline at end of file
diff --git a/yarn.lock b/yarn.lock
index df6f8f2..56738d8 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -2929,6 +2929,11 @@ core-js@^3.4.0:
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.26.1.tgz#7a9816dabd9ee846c1c0fe0e8fcad68f3709134e"
integrity sha512-21491RRQVzUn0GGM9Z1Jrpr6PNPxPi+Za8OM9q4tksTSnlbXXGKK1nXNg/QvwFYettXvSX6zWKCtHHfjN4puyA==
+core-js@^3.4.2:
+ version "3.27.1"
+ resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.27.1.tgz#23cc909b315a6bb4e418bf40a52758af2103ba46"
+ integrity sha512-GutwJLBChfGCpwwhbYoqfv03LAfmiz7e7D/BNxzeMxwQf10GRSzqiOjx7AmtEk+heiD/JWmBuyBPgFtx0Sg1ww==
+
core-util-is@1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
@@ -6305,6 +6310,11 @@ object-keys@^1.1.1:
resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
+object-to-formdata@3.0.9:
+ version "3.0.9"
+ resolved "https://registry.yarnpkg.com/object-to-formdata/-/object-to-formdata-3.0.9.tgz#40e3314522345789259738811c0222b7d6e556e9"
+ integrity sha512-1JDHRFSpk6wzhPBAAqdVncdvbjZ+bjB0tioruNdKn8UyudBBXiBxRa7PJyvYqp4ioEKX98dEOX9Fw1RxA+vLzg==
+
object-visit@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
@@ -7613,6 +7623,15 @@ react-dom@^18.2.0:
loose-envify "^1.1.0"
scheduler "^0.23.0"
+react-image-crop@8.6.4:
+ version "8.6.4"
+ resolved "https://registry.yarnpkg.com/react-image-crop/-/react-image-crop-8.6.4.tgz#51289c22baf7d116575102e885f879af71376388"
+ integrity sha512-5buyhUg9slzW+QGvN2dbpGSI1VqPxxmfEwe19TZXUB7LjW5+ljZOnrTSsteIzeBqmz6ngVucc8l+OrwgcDOSNg==
+ dependencies:
+ clsx "^1.0.4"
+ core-js "^3.4.2"
+ prop-types "^15.7.2"
+
react-is@^16.13.1, react-is@^16.7.0:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"