Skip to content

Commit

Permalink
feat: adding drag & drop file upload
Browse files Browse the repository at this point in the history
file upload and validation

File upload progression

adding a functional drag and drop upload field
updating builder
  • Loading branch information
gustavs-gutmanis committed Aug 2, 2021
1 parent a2171f8 commit 196ef76
Show file tree
Hide file tree
Showing 57 changed files with 5,395 additions and 1,071 deletions.
2 changes: 1 addition & 1 deletion .php_cs.dist → .php-cs-fixer.dist.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
$finder = PhpCsFixer\Finder::create()
->in(__DIR__ . '/packages/plugin');

return PhpCsFixer\Config::create()
return (new PhpCsFixer\Config())
->setRules([
'@Symfony' => true,
'@Symfony:risky' => true,
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
},
"require-dev": {
"phpunit/phpunit": "^9.3.0",
"friendsofphp/php-cs-fixer": "^2.16",
"friendsofphp/php-cs-fixer": "^2.19",
"brainmaestro/composer-git-hooks": "^2.8"
},
"autoload": {
Expand Down
320 changes: 166 additions & 154 deletions composer.lock

Large diffs are not rendered by default.

3,310 changes: 2,777 additions & 533 deletions package-lock.json

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,29 @@
"private": true,
"description": "Freeform plugin for Craft CMS",
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^4.28.0",
"@typescript-eslint/parser": "^4.28.0",
"babel-eslint": "^10.1.0",
"browserslist": ">=4.16.5",
"eslint": "^7.20.0",
"eslint-config-prettier": "^7.2.0",
"eslint-config-react": "^1.1.7",
"eslint-plugin-babel": "^5.3.1",
"eslint-plugin-import": "^2.23.4",
"eslint-plugin-prettier": "^3.3.1",
"eslint-plugin-react": "^7.22.0",
"eslint-plugin-simple-import-sort": "^7.0.0",
"hosted-git-info": ">=2.8.9",
"ini": ">=2.0.0",
"lerna": "^3.22.1",
"postcss": ">=8.2.10",
"prettier": "^2.2.1",
"prettier-eslint": "^12.0.0",
"typescript": "^4.1.5"
},
"scripts": {
"dev": "lerna run --parallel dev",
"front-end": "lerna run --parallel dev --scope=@ff/{scripts,styles}",
"build": "lerna run --parallel build",
"format": "prettier --write '**/*.{ts,tsx,md,json,js,jsx,css}'",
"format:verify": "prettier --list-different '**/*.{ts,tsx,md,json,js,jsx,css}'",
Expand Down
2 changes: 2 additions & 0 deletions packages/builder/src/components/Composer/Field.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import CheckboxGroup from './FieldTypes/CheckboxGroup';
import Confirmation from './FieldTypes/Confirmation';
import Datetime from './FieldTypes/Datetime';
import DynamicRecipients from './FieldTypes/DynamicRecipients';
import DragAndDropFile from './FieldTypes/DragAndDropFile';
import Email from './FieldTypes/Email';
import File from './FieldTypes/File';
import Hidden from './FieldTypes/Hidden';
Expand Down Expand Up @@ -67,6 +68,7 @@ const fieldTypes = {
cc_number: CreditCardNumber,
cc_cvc: CreditCardCvc,
cc_exp_date: CreditCardExpDate,
drag_and_drop_file: DragAndDropFile,
};

export default class Field extends Component {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import PropTypes from 'prop-types';
import React from 'react';
import { FILE } from './../../../constants/FieldTypes';
import Badge from './Components/Badge';
import HtmlInput from './HtmlInput';
import styled from 'styled-components';

const Wrapper = styled.div`
padding: 10px 0;
border-radius: 5px;
border: 3px dashed grey;
background: lightgrey;
text-align: center;
`;

export default class DragAndDropFile extends HtmlInput {
static propTypes = {
properties: PropTypes.shape({
label: PropTypes.string.isRequired,
required: PropTypes.bool.isRequired,
assetSourceId: PropTypes.number,
}).isRequired,
};

getClassName() {
return 'DragAndDropFile';
}

getType() {
return FILE;
}

getBadges() {
const badges = super.getBadges();
const {
properties: { assetSourceId },
} = this.props;

if (!assetSourceId) {
badges.push(<Badge key={'asset'} label="No Asset Source" type={Badge.WARNING} />);
}

return badges;
}

renderInput() {
return <Wrapper>Drag & Drop a file</Wrapper>;
}
}
2 changes: 0 additions & 2 deletions packages/builder/src/components/PropertyEditor/File.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import BasePropertyEditor from './BasePropertyEditor';
import { AttributeEditorProperty } from './PropertyItems';
import CheckboxListProperty from './PropertyItems/CheckboxListProperty';
import CheckboxProperty from './PropertyItems/CheckboxProperty';
import ExternalOptionsProperty from './PropertyItems/ExternalOptionsProperty';
import SelectProperty from './PropertyItems/SelectProperty';
import TextareaProperty from './PropertyItems/TextareaProperty';
import TextProperty from './PropertyItems/TextProperty';
Expand Down Expand Up @@ -56,7 +55,6 @@ export default class File extends BasePropertyEditor {

const {
properties: {
type,
label,
handle,
required,
Expand Down
1 change: 1 addition & 0 deletions packages/builder/src/containers/PropertyEditor.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ const propertyTypes = {
signature: Signature,
table: Table,
invisible: Invisible,
drag_and_drop_file: File,
};

const crmPropertyTypes = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Solspace\Freeform\Bundles\Form\Context\Request;

use Solspace\Freeform\Elements\Submission;
use Solspace\Freeform\Events\Forms\HandleRequestEvent;
use Solspace\Freeform\Events\Forms\RenderTagEvent;
use Solspace\Freeform\Fields\CheckboxField;
use Solspace\Freeform\Fields\DynamicRecipientField;
Expand All @@ -16,18 +17,33 @@ class EditElementContext

public function __construct()
{
Event::on(Form::class, Form::EVENT_RENDER_BEFORE_OPEN_TAG, [$this, 'handleRequest']);
Event::on(Form::class, Form::EVENT_BEFORE_HANDLE_REQUEST, [$this, 'handleRequest']);
Event::on(Form::class, Form::EVENT_RENDER_BEFORE_OPEN_TAG, [$this, 'handleRender']);
}

public function handleRequest(RenderTagEvent $event)
public function handleRequest(HandleRequestEvent $event)
{
$form = $event->getForm();
$submissionToken = $form->getPropertyBag()->get(self::SUBMISSION_TOKEN_KEY);
if (!$submissionToken) {
$token = $form->getAssociatedSubmissionToken();

$this->applySubmissionToForm($form, $token);
}

public function handleRender(RenderTagEvent $event)
{
$form = $event->getForm();
$token = $form->getPropertyBag()->get(self::SUBMISSION_TOKEN_KEY);

$this->applySubmissionToForm($form, $token);
}

private function applySubmissionToForm(Form $form, string $token = null)
{
if (!$token) {
return;
}

$submission = Freeform::getInstance()->submissions->getSubmissionByToken($submissionToken);
$submission = Freeform::getInstance()->submissions->getSubmissionByToken($token);
if (!$submission instanceof Submission) {
return;
}
Expand Down
15 changes: 10 additions & 5 deletions packages/plugin/src/Bundles/Form/Context/Request/PostContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

namespace Solspace\Freeform\Bundles\Form\Context\Request;

use Solspace\Freeform\Bundles\GraphQL\Interfaces\FieldInterface;
use Solspace\Freeform\Events\Fields\TransformValueEvent;
use Solspace\Freeform\Events\Forms\HandleRequestEvent;
use Solspace\Freeform\Fields\CheckboxField;
use Solspace\Freeform\Library\Composer\Components\Form;
use yii\base\Event;

Expand All @@ -19,17 +20,21 @@ public function handleRequest(HandleRequestEvent $event)
$form = $event->getForm();
$request = $event->getRequest();

if ($request->getHeaders()->get('Freeform-Preflight')) {
return;
}

if ('POST' !== $request->getMethod() || !$form->isPagePosted()) {
return;
}

foreach ($form->getCurrentPage()->getFields() as $field) {
$postedValue = $request->post($field->getHandle());
if ($field instanceof CheckboxField) {
$postedValue = (bool) $postedValue;
}

$field->setValue($postedValue);
$event = new TransformValueEvent($field, $postedValue);
Event::trigger(FieldInterface::class, FieldInterface::EVENT_TRANSFORM_FROM_POST, $event);

$field->setValue($event->getValue());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

namespace Solspace\Freeform\Bundles\Form\Fields\CheckboxField;

use Solspace\Freeform\Bundles\GraphQL\Interfaces\FieldInterface;
use Solspace\Freeform\Events\Fields\TransformValueEvent;
use Solspace\Freeform\Fields\CheckboxField;
use Solspace\Freeform\Library\Bundles\BundleInterface;
use yii\base\Event;

class CheckboxFieldBundle implements BundleInterface
{
public function __construct()
{
Event::on(FieldInterface::class, FieldInterface::EVENT_TRANSFORM_FROM_POST, [$this, 'handleTransform']);
}

public function handleTransform(TransformValueEvent $event)
{
if (!$event instanceof CheckboxField) {
return;
}

$event->setValue((bool) $event->getValue());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

namespace Solspace\Freeform\Bundles\Form\Fields\FileUpload;

use Solspace\Freeform\Bundles\GraphQL\Interfaces\FieldInterface;
use Solspace\Freeform\Events\Fields\TransformValueEvent;
use Solspace\Freeform\Events\Forms\SubmitEvent;
use Solspace\Freeform\Fields\FileUploadField;
use Solspace\Freeform\Fields\Pro\DragAndDropFileField;
use Solspace\Freeform\Library\Bundles\BundleInterface;
use Solspace\Freeform\Library\Composer\Components\Form;
use Solspace\Freeform\Records\UnfinalizedFileRecord;
use yii\base\Event;

class FileUploadBundle implements BundleInterface
{
public function __construct()
{
Event::on(Form::class, Form::EVENT_AFTER_SUBMIT, [$this, 'finalizeFiles']);
Event::on(FieldInterface::class, FieldInterface::EVENT_TRANSFORM_FROM_POST, [$this, 'handleDnDPost']);
}

public function finalizeFiles(SubmitEvent $event)
{
$form = $event->getForm();
$submission = $event->getSubmission();

// Handle only stored submissions
if (!$submission->id) {
return;
}

$fields = $form->getLayout()->getFields(FileUploadField::class);
$assetIds = [];
foreach ($fields as $field) {
$assetIds = array_merge($assetIds, $field->getValue());
}

if (empty($assetIds)) {
return;
}

$records = UnfinalizedFileRecord::findAll(['assetId' => $assetIds]);
foreach ($records as $record) {
$record->delete();
}
}

public function handleDnDPost(TransformValueEvent $event)
{
$field = $event->getField();
if (!$field instanceof DragAndDropFileField) {
return;
}

$uids = $event->getValue();
if (!\is_array($uids)) {
$event->setValue([]);

return;
}

$ids = [];
foreach ($uids as $uid) {
$asset = \Craft::$app->getElements()->getElementByUid($uid);
$ids[] = $asset->id;
}

$event->setValue($ids);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,16 @@
use Solspace\Freeform\Fields\Pro\PhoneField;
use Solspace\Freeform\Fields\Pro\SignatureField;
use Solspace\Freeform\Library\Bundles\BundleInterface;
use Solspace\Freeform\Services\FormsService;
use Solspace\Freeform\Library\Composer\Components\Form;
use yii\base\Event;

class OptionalFieldJavascriptBundle implements BundleInterface
{
public function __construct()
{
Event::on(
FormsService::class,
FormsService::EVENT_ATTACH_FORM_ATTRIBUTES,
Form::class,
Form::EVENT_ATTACH_TAG_ATTRIBUTES,
function (AttachFormAttributesEvent $event) {
$form = $event->getForm();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@

class FieldInterface extends AbstractInterface
{
const EVENT_TRANSFORM_FROM_POST = 'transformFromPost';
const EVENT_TRANSFORM_FROM_STORAGE = 'transformFromStorage';
const EVENT_TRANSFORM_FROM_DATABASE = 'transformFromDatabase';

public static function getName(): string
{
return 'FreeformFormFieldInterface';
Expand Down
Loading

0 comments on commit 196ef76

Please sign in to comment.