From a7c9e8dec1186c8685809e7a609eca32a93e9f74 Mon Sep 17 00:00:00 2001 From: Josh Torres Date: Wed, 4 Oct 2023 16:15:17 -0700 Subject: [PATCH 1/4] - add initial config - add files from forms module --- .github/FUNDING.yml | 2 +- .github/ISSUE_TEMPLATE/config.yml | 6 +- .github/SECURITY.md | 2 +- CHANGELOG.md | 2 +- LICENSE.md | 2 +- README.md | 32 +- bin/build.js | 2 +- composer.json | 32 +- config/skeleton.php | 6 - configure.php | 368 ------------------ database/factories/ModelFactory.php | 2 +- .../migrations/create_skeleton_table.php.stub | 19 - package.json | 6 +- phpunit.xml.dist | 2 +- resources/lang/en/skeleton.php | 6 - src/Commands/SkeletonCommand.php | 19 - src/Config/.gitkeep | 0 src/Config/config.php | 5 + src/Console/.gitkeep | 0 src/Database/Migrations/.gitkeep | 0 .../2022_09_23_195505_create_forms_table.php | 72 ++++ ..._11_070610_add_for_to_form_types_table.php | 32 ++ ...210219_create_form_notifications_table.php | 40 ++ src/Database/Seeders/.gitkeep | 0 src/Database/Seeders/FormsDatabaseSeeder.php | 43 ++ src/Database/factories/.gitkeep | 0 src/Emails/.gitkeep | 0 src/Events/.gitkeep | 0 src/Facades/Skeleton.php | 16 - src/Http/Controllers/.gitkeep | 0 src/Http/Controllers/FormsController.php | 84 ++++ src/Http/Livewire/Builder.php | 105 +++++ src/Http/Livewire/Form.php | 135 +++++++ src/Http/Livewire/TeamApplicationForm.php | 52 +++ src/Http/Livewire/UserRegistrationForm.php | 90 +++++ src/Http/Middleware/.gitkeep | 0 src/Http/Requests/.gitkeep | 0 src/Jobs/.gitkeep | 0 src/Jobs/SendFormNotificationsJob.php | 72 ++++ src/Listeners/.gitkeep | 0 src/Models/.gitkeep | 0 src/Models/Form.php | 64 +++ src/Models/FormNotification.php | 54 +++ src/Models/FormSubmission.php | 45 +++ src/Models/FormTemplate.php | 37 ++ src/Models/FormType.php | 59 +++ src/Notifications/.gitkeep | 0 .../FormReminderNotification.php | 78 ++++ src/Policies/.gitkeep | 0 src/Policies/FormPolicy.php | 108 +++++ src/Policies/FormSubmissionPolicy.php | 108 +++++ src/Policies/FormTypePolicy.php | 108 +++++ src/Providers/.gitkeep | 0 src/Providers/FormsServiceProvider.php | 113 ++++++ src/Providers/RouteServiceProvider.php | 69 ++++ src/Repositories/.gitkeep | 0 src/Resources/assets/.gitkeep | 0 src/Resources/assets/js/app.js | 0 src/Resources/assets/sass/app.scss | 0 src/Resources/lang/.gitkeep | 0 src/Resources/views/.gitkeep | 0 src/Resources/views/components/.gitkeep | 0 src/Resources/views/index.blade.php | 9 + src/Resources/views/layouts/master.blade.php | 19 + .../views/livewire/builder.blade.php | 11 + .../views/livewire/form-submission.blade.php | 5 + src/Resources/views/livewire/form.blade.php | 21 + src/Routes/.gitkeep | 0 src/Routes/api.php | 18 + src/Routes/web.php | 18 + src/Rules/.gitkeep | 0 src/Skeleton.php | 7 - src/SkeletonPlugin.php | 37 -- src/SkeletonServiceProvider.php | 154 -------- src/SkeletonTheme.php | 39 -- src/Testing/TestsSkeleton.php | 13 - src/Tests/Feature/.gitkeep | 0 src/Tests/Unit/.gitkeep | 0 src/Traits/Livewire/WithFormBuilder.php | 148 +++++++ src/Traits/Livewire/WithFormManagement.php | 88 +++++ src/Transformers/.gitkeep | 0 src/View/Component/.gitkeep | 0 tests/Pest.php | 2 +- tests/TestCase.php | 10 +- 84 files changed, 1956 insertions(+), 740 deletions(-) delete mode 100644 config/skeleton.php delete mode 100644 configure.php delete mode 100644 database/migrations/create_skeleton_table.php.stub delete mode 100644 resources/lang/en/skeleton.php delete mode 100644 src/Commands/SkeletonCommand.php create mode 100644 src/Config/.gitkeep create mode 100644 src/Config/config.php create mode 100644 src/Console/.gitkeep create mode 100644 src/Database/Migrations/.gitkeep create mode 100644 src/Database/Migrations/2022_09_23_195505_create_forms_table.php create mode 100644 src/Database/Migrations/2022_11_11_070610_add_for_to_form_types_table.php create mode 100644 src/Database/Migrations/2022_11_30_210219_create_form_notifications_table.php create mode 100644 src/Database/Seeders/.gitkeep create mode 100644 src/Database/Seeders/FormsDatabaseSeeder.php create mode 100644 src/Database/factories/.gitkeep create mode 100644 src/Emails/.gitkeep create mode 100644 src/Events/.gitkeep delete mode 100644 src/Facades/Skeleton.php create mode 100644 src/Http/Controllers/.gitkeep create mode 100644 src/Http/Controllers/FormsController.php create mode 100644 src/Http/Livewire/Builder.php create mode 100644 src/Http/Livewire/Form.php create mode 100644 src/Http/Livewire/TeamApplicationForm.php create mode 100644 src/Http/Livewire/UserRegistrationForm.php create mode 100644 src/Http/Middleware/.gitkeep create mode 100644 src/Http/Requests/.gitkeep create mode 100644 src/Jobs/.gitkeep create mode 100644 src/Jobs/SendFormNotificationsJob.php create mode 100644 src/Listeners/.gitkeep create mode 100644 src/Models/.gitkeep create mode 100644 src/Models/Form.php create mode 100644 src/Models/FormNotification.php create mode 100644 src/Models/FormSubmission.php create mode 100644 src/Models/FormTemplate.php create mode 100644 src/Models/FormType.php create mode 100644 src/Notifications/.gitkeep create mode 100644 src/Notifications/FormReminderNotification.php create mode 100644 src/Policies/.gitkeep create mode 100644 src/Policies/FormPolicy.php create mode 100644 src/Policies/FormSubmissionPolicy.php create mode 100644 src/Policies/FormTypePolicy.php create mode 100644 src/Providers/.gitkeep create mode 100644 src/Providers/FormsServiceProvider.php create mode 100644 src/Providers/RouteServiceProvider.php create mode 100644 src/Repositories/.gitkeep create mode 100644 src/Resources/assets/.gitkeep create mode 100644 src/Resources/assets/js/app.js create mode 100644 src/Resources/assets/sass/app.scss create mode 100644 src/Resources/lang/.gitkeep create mode 100644 src/Resources/views/.gitkeep create mode 100644 src/Resources/views/components/.gitkeep create mode 100644 src/Resources/views/index.blade.php create mode 100644 src/Resources/views/layouts/master.blade.php create mode 100644 src/Resources/views/livewire/builder.blade.php create mode 100644 src/Resources/views/livewire/form-submission.blade.php create mode 100644 src/Resources/views/livewire/form.blade.php create mode 100644 src/Routes/.gitkeep create mode 100644 src/Routes/api.php create mode 100644 src/Routes/web.php create mode 100644 src/Rules/.gitkeep delete mode 100644 src/Skeleton.php delete mode 100644 src/SkeletonPlugin.php delete mode 100644 src/SkeletonServiceProvider.php delete mode 100644 src/SkeletonTheme.php delete mode 100644 src/Testing/TestsSkeleton.php create mode 100644 src/Tests/Feature/.gitkeep create mode 100644 src/Tests/Unit/.gitkeep create mode 100644 src/Traits/Livewire/WithFormBuilder.php create mode 100644 src/Traits/Livewire/WithFormManagement.php create mode 100644 src/Transformers/.gitkeep create mode 100644 src/View/Component/.gitkeep diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index c68765b..3b2de96 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1 +1 @@ -github: :vendor_name +github: omnia-digital diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 96701be..ca8e09b 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,11 +1,11 @@ blank_issues_enabled: false contact_links: - name: Ask a question - url: https://github.com/:vendor_name/:package_name/discussions/new?category=q-a + url: https://github.com/omnia-digital/catalyst-forms-plugin/discussions/new?category=q-a about: Ask the community for help - name: Request a feature - url: https://github.com/:vendor_name/:package_name/discussions/new?category=ideas + url: https://github.com/omnia-digital/catalyst-forms-plugin/discussions/new?category=ideas about: Share ideas for new features - name: Report a security issue - url: https://github.com/:vendor_name/:package_name/security/policy + url: https://github.com/omnia-digital/catalyst-forms-plugin/security/policy about: Learn how to notify us for sensitive bugs diff --git a/.github/SECURITY.md b/.github/SECURITY.md index 12ab7c2..8f8735f 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -1,3 +1,3 @@ # Security Policy -If you discover any security related issues, please email author@domain.com instead of using the issue tracker. +If you discover any security related issues, please email josht@omniadigital.io instead of using the issue tracker. diff --git a/CHANGELOG.md b/CHANGELOG.md index 767365d..c56cd54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -All notable changes to `:package_name` will be documented in this file. +All notable changes to `catalyst-forms-plugin` will be documented in this file. ## 1.0.0 - 202X-XX-XX diff --git a/LICENSE.md b/LICENSE.md index 58c9ad4..a734718 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) :vendor_name +Copyright (c) omnia-digital Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 02d882d..b11bdf4 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,11 @@ -# :package_description +# Forms plugin for Catalyst -[![Latest Version on Packagist](https://img.shields.io/packagist/v/:vendor_slug/:package_slug.svg?style=flat-square)](https://packagist.org/packages/:vendor_slug/:package_slug) -[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/:vendor_slug/:package_slug/run-tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/:vendor_slug/:package_slug/actions?query=workflow%3Arun-tests+branch%3Amain) -[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/:vendor_slug/:package_slug/fix-php-code-style-issues.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/:vendor_slug/:package_slug/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain) -[![Total Downloads](https://img.shields.io/packagist/dt/:vendor_slug/:package_slug.svg?style=flat-square)](https://packagist.org/packages/:vendor_slug/:package_slug) +[![Latest Version on Packagist](https://img.shields.io/packagist/v/omnia-digital/catalyst-forms-plugin.svg?style=flat-square)](https://packagist.org/packages/omnia-digital/catalyst-forms-plugin) +[![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/omnia-digital/catalyst-forms-plugin/run-tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/omnia-digital/catalyst-forms-plugin/actions?query=workflow%3Arun-tests+branch%3Amain) +[![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/omnia-digital/catalyst-forms-plugin/fix-php-code-style-issues.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/omnia-digital/catalyst-forms-plugin/actions?query=workflow%3A"Fix+PHP+code+style+issues"+branch%3Amain) +[![Total Downloads](https://img.shields.io/packagist/dt/omnia-digital/catalyst-forms-plugin.svg?style=flat-square)](https://packagist.org/packages/omnia-digital/catalyst-forms-plugin) - ---- -This repo can be used to scaffold a Filament plugin. Follow these steps to get started: -1. Press the "Use this template" button at the top of this repo to create a new repo with the contents of this skeleton. -2. Run "php ./configure.php" to run a script that will replace all placeholders throughout all the files. -3. Make something great! ---- - This is where your description should go. Limit it to a paragraph or two. Consider adding a small example. @@ -22,26 +14,26 @@ This is where your description should go. Limit it to a paragraph or two. Consid You can install the package via composer: ```bash -composer require :vendor_slug/:package_slug +composer require omnia-digital/catalyst-forms-plugin ``` You can publish and run the migrations with: ```bash -php artisan vendor:publish --tag=":package_slug-migrations" +php artisan vendor:publish --tag="catalyst-forms-plugin-migrations" php artisan migrate ``` You can publish the config file with: ```bash -php artisan vendor:publish --tag=":package_slug-config" +php artisan vendor:publish --tag="catalyst-forms-plugin-config" ``` Optionally, you can publish the views using ```bash -php artisan vendor:publish --tag=":package_slug-views" +php artisan vendor:publish --tag="catalyst-forms-plugin-views" ``` This is the contents of the published config file: @@ -54,8 +46,8 @@ return [ ## Usage ```php -$variable = new VendorName\Skeleton(); -echo $variable->echoPhrase('Hello, VendorName!'); +$catalystFormsPlugin = new OmniaDigital\CatalystFormsPlugin(); +echo $catalystFormsPlugin->echoPhrase('Hello, OmniaDigital!'); ``` ## Testing @@ -78,7 +70,7 @@ Please review [our security policy](../../security/policy) on how to report secu ## Credits -- [:author_name](https://github.com/:author_username) +- [Josh Torres](https://github.com/joshtorres) - [All Contributors](../../contributors) ## License diff --git a/bin/build.js b/bin/build.js index 913baf4..172a4f2 100644 --- a/bin/build.js +++ b/bin/build.js @@ -46,5 +46,5 @@ const defaultOptions = { compile({ ...defaultOptions, entryPoints: ['./resources/js/index.js'], - outfile: './resources/dist/skeleton.js', + outfile: './resources/dist/catalyst-forms-plugin.js', }) diff --git a/composer.json b/composer.json index 53946f2..4dcc9d0 100644 --- a/composer.json +++ b/composer.json @@ -1,29 +1,27 @@ { - "name": ":vendor_slug/:package_slug", - "description": ":package_description", + "name": "omnia-digital/catalyst-forms-plugin", + "description": "Forms plugin for Catalyst", "keywords": [ - ":vendor_name", + "omnia-digital", "laravel", - ":package_slug" + "catalyst-forms-plugin" ], - "homepage": "https://github.com/:vendor_slug/:package_slug", + "homepage": "https://github.com/omnia-digital/catalyst-forms-plugin", "support": { - "issues": "https://github.com/:vendor_slug/:package_slug/issues", - "source": "https://github.com/:vendor_slug/:package_slug" + "issues": "https://github.com/omnia-digital/catalyst-forms-plugin/issues", + "source": "https://github.com/omnia-digital/catalyst-forms-plugin" }, "license": "MIT", "authors": [ { - "name": ":author_name", - "email": "author@domain.com", + "name": "Josh Torres", + "email": "josht@omniadigital.io", "role": "Developer" } ], "require": { "php": "^8.1", "filament/filament": "^3.0", - "filament/forms": "^3.0", - "filament/tables": "^3.0", "spatie/laravel-package-tools": "^1.15.0", "illuminate/contracts": "^10.0" }, @@ -42,13 +40,13 @@ }, "autoload": { "psr-4": { - "VendorName\\Skeleton\\": "src/", - "VendorName\\Skeleton\\Database\\Factories\\": "database/factories/" + "OmniaDigital\\CatalystFormsPlugin\\": "src/", + "OmniaDigital\\CatalystFormsPlugin\\Database\\Factories\\": "database/factories/" } }, "autoload-dev": { "psr-4": { - "VendorName\\Skeleton\\Tests\\": "tests/" + "OmniaDigital\\CatalystFormsPlugin\\Tests\\": "tests/" } }, "scripts": { @@ -68,13 +66,13 @@ "extra": { "laravel": { "providers": [ - "VendorName\\Skeleton\\SkeletonServiceProvider" + "OmniaDigital\\CatalystFormsPlugin\\CatalystFormsPluginServiceProvider" ], "aliases": { - "Skeleton": "VendorName\\Skeleton\\Facades\\Skeleton" + "CatalystFormsPlugin": "OmniaDigital\\CatalystFormsPlugin\\Facades\\CatalystFormsPlugin" } } }, "minimum-stability": "dev", "prefer-stable": true -} +} \ No newline at end of file diff --git a/config/skeleton.php b/config/skeleton.php deleted file mode 100644 index 7e74186..0000000 --- a/config/skeleton.php +++ /dev/null @@ -1,6 +0,0 @@ -" : '') . "\e[0m"); -writeln("Namespace : \e[0;36m$vendorNamespace\\$className\e[0m"); -writeln("Class name : \e[0;36m$className\e[0m"); -writeln('---'); -writeln("\e[1;37mPackages & Utilities\e[0m"); -writeln('Larastan/PhpStan : ' . ($usePhpStan ? "\e[0;32mYes" : "\e[0;31mNo") . "\e[0m"); -writeln('Pint : ' . ($usePint ? "\e[0;32mYes" : "\e[0;31mNo") . "\e[0m"); -writeln('Use Dependabot : ' . ($useDependabot ? "\e[0;32mYes" : "\e[0;31mNo") . "\e[0m"); -writeln('Use Ray : ' . ($useLaravelRay ? "\e[0;32mYes" : "\e[0;31mNo") . "\e[0m"); -writeln('Auto-Changelog : ' . ($useUpdateChangelogWorkflow ? "\e[0;32mYes" : "\e[0;31mNo") . "\e[0m"); -if ($formsOnly) { - writeln("Filament/Forms : \e[0;32mYes\e[0m"); -} elseif ($tablesOnly) { - writeln("Filament/Tables : \e[0;32mYes\e[0m"); -} else { - writeln("Filament/Filament : \e[0;32mYes\e[0m"); -} -writeln('------'); -writeln("\r"); -writeln('This script will replace the above values in all relevant files in the project directory.'); -writeln("\r"); - -if (! confirm('Modify files?', true)) { - exit(1); -} - -if ($formsOnly) { - safeUnlink(__DIR__ . '/src/SkeletonTheme.php'); - safeUnlink(__DIR__ . '/src/SkeletonPlugin.php'); - - removeComposerDeps([ - 'filament/filament', - 'filament/tables', - ], 'require'); -} elseif ($tablesOnly) { - safeUnlink(__DIR__ . '/src/SkeletonTheme.php'); - safeUnlink(__DIR__ . '/src/SkeletonPlugin.php'); - - removeComposerDeps([ - 'filament/filament', - 'filament/forms', - ], 'require'); -} else { - if ($isTheme) { - safeUnlink(__DIR__ . '/src/SkeletonServiceProvider.php'); - safeUnlink(__DIR__ . '/src/SkeletonPlugin.php'); - safeUnlink(__DIR__ . '/src/Skeleton.php'); - removeDirectory(__DIR__ . '/bin'); - removeDirectory(__DIR__ . '/config'); - removeDirectory(__DIR__ . '/database'); - removeDirectory(__DIR__ . '/stubs'); - removeDirectory(__DIR__ . '/resources/js'); - removeDirectory(__DIR__ . '/resources/lang'); - removeDirectory(__DIR__ . '/resources/views'); - removeDirectory(__DIR__ . '/src/Commands'); - removeDirectory(__DIR__ . '/src/Facades'); - removeDirectory(__DIR__ . '/src/Testing'); - - setupPackageJsonForTheme(); - - } else { - safeUnlink(__DIR__ . '/src/SkeletonTheme.php'); - } - - removeComposerDeps([ - 'filament/forms', - 'filament/tables', - ], 'require'); -} - -$files = (str_starts_with(strtoupper(PHP_OS), 'WIN') ? replaceForWindows() : replaceForAllOtherOSes()); - -foreach ($files as $file) { - replaceInFile($file, [ - ':author_name' => $authorName, - ':author_username' => $authorUsername, - 'author@domain.com' => $authorEmail, - ':vendor_name' => $vendorName, - ':vendor_slug' => $vendorSlug, - 'VendorName' => $vendorNamespace, - ':package_name' => $packageName, - ':package_slug' => $packageSlug, - ':package_slug_without_prefix' => $packageSlugWithoutPrefix, - 'Skeleton' => $className, - 'skeleton' => $packageSlug, - 'migration_table_name' => titleSnake($packageSlug), - 'variable' => $variableName, - ':package_description' => $description, - ]); - - match (true) { - str_contains($file, determineSeparator('src/Skeleton.php')) => rename($file, determineSeparator('./src/' . $className . '.php')), - str_contains($file, determineSeparator('src/SkeletonServiceProvider.php')) => rename($file, determineSeparator('./src/' . $className . 'ServiceProvider.php')), - str_contains($file, determineSeparator('src/SkeletonTheme.php')) => rename($file, determineSeparator('./src/' . $className . 'Theme.php')), - str_contains($file, determineSeparator('src/SkeletonPlugin.php')) => rename($file, determineSeparator('./src/' . $className . 'Plugin.php')), - str_contains($file, determineSeparator('src/Facades/Skeleton.php')) => rename($file, determineSeparator('./src/Facades/' . $className . '.php')), - str_contains($file, determineSeparator('src/Commands/SkeletonCommand.php')) => rename($file, determineSeparator('./src/Commands/' . $className . 'Command.php')), - str_contains($file, determineSeparator('src/Testing/TestsSkeleton.php')) => rename($file, determineSeparator('./src/Testing/Tests' . $className . '.php')), - str_contains($file, determineSeparator('database/migrations/create_skeleton_table.php.stub')) => rename($file, determineSeparator('./database/migrations/create_' . titleSnake($packageSlugWithoutPrefix) . '_table.php.stub')), - str_contains($file, determineSeparator('config/skeleton.php')) => rename($file, determineSeparator('./config/' . $packageSlugWithoutPrefix . '.php')), - str_contains($file, determineSeparator('resources/lang/en/skeleton.php')) => rename($file, determineSeparator('./resources/lang/en/' . $packageSlugWithoutPrefix . '.php')), - str_contains($file, 'README.md') => removeTag($file, 'delete'), - default => [], - }; -} - -if (! $useDependabot) { - safeUnlink(__DIR__ . '/.github/dependabot.yml'); - safeUnlink(__DIR__ . '/.github/workflows/dependabot-auto-merge.yml'); -} - -if (! $useLaravelRay) { - removeComposerDeps(['spatie/laravel-ray'], 'require-dev'); -} - -if (! $usePhpStan) { - safeUnlink(__DIR__ . '/phpstan.neon.dist'); - safeUnlink(__DIR__ . '/phpstan-baseline.neon'); - safeUnlink(__DIR__ . '/.github/workflows/phpstan.yml'); - - removeComposerDeps([ - 'phpstan/extension-installer', - 'phpstan/phpstan-deprecation-rules', - 'phpstan/phpstan-phpunit', - 'nunomaduro/larastan', - ], 'require-dev'); - - removeComposerDeps(['analyse'], 'scripts'); -} - -if (! $usePint) { - safeUnlink(__DIR__ . '/.github/workflows/fix-php-code-style-issues.yml'); - safeUnlink(__DIR__ . '/pint.json'); - - removeComposerDeps([ - 'laravel/pint', - ], 'require-dev'); - - removeComposerDeps(['format'], 'scripts'); -} - -if (! $useUpdateChangelogWorkflow) { - safeUnlink(__DIR__ . '/.github/workflows/update-changelog.yml'); -} - -confirm('Execute `composer install`?') && run('composer install'); - -if (confirm('Let this script delete itself?', true)) { - unlink(__FILE__); -} - -function ask(string $question, string $default = ''): string -{ - $def = $default ? "\e[0;33m ($default)" : ''; - $answer = readline("\e[0;32m" . $question . $def . ": \e[0m"); - - if (! $answer) { - return $default; - } - - return $answer; -} - -function confirm(string $question, bool $default = false): bool -{ - $answer = ask($question, ($default ? 'Y/n' : 'y/N')); - - if (strtolower($answer) === 'y/n') { - return $default; - } - - return strtolower($answer) === 'y'; -} - -function writeln(string $line): void -{ - echo $line . PHP_EOL; -} - -function run(string $command): string -{ - return trim((string) shell_exec($command)); -} - -function slugify(string $subject): string -{ - return strtolower(trim(preg_replace('/[^A-Za-z0-9-]+/', '-', $subject), '-')); -} - -function titleCase(string $subject): string -{ - return str_replace(' ', '', ucwords(str_replace(['-', '_'], ' ', $subject))); -} - -function titleSnake(string $subject, string $replace = '_'): string -{ - return str_replace(['-', '_'], $replace, $subject); -} - -function replaceInFile(string $file, array $replacements): void -{ - $contents = file_get_contents($file); - - file_put_contents( - $file, - str_replace( - array_keys($replacements), - array_values($replacements), - $contents - ) - ); -} - -function removePrefix(string $prefix, string $content): string -{ - if (str_starts_with($content, $prefix)) { - return substr($content, strlen($prefix)); - } - - return $content; -} - -function removeComposerDeps(array $names, string $location): void -{ - $data = json_decode(file_get_contents(__DIR__ . '/composer.json'), true); - - foreach ($data[$location] as $name => $version) { - if (in_array($name, $names, true)) { - unset($data[$location][$name]); - } - } - - file_put_contents(__DIR__ . '/composer.json', json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)); -} - -function removeNpmDeps(array $names, string $location): void -{ - $data = json_decode(file_get_contents(__DIR__ . '/package.json'), true); - - foreach ($data[$location] as $name => $version) { - if (in_array($name, $names, true)) { - unset($data[$location][$name]); - } - } - - file_put_contents(__DIR__ . '/package.json', json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | - JSON_UNESCAPED_UNICODE)); -} - -function removeTag(string $file, string $tag): void -{ - $contents = file_get_contents($file); - - file_put_contents( - $file, - preg_replace('/.*/s', '', $contents) ?: $contents - ); -} - -function setupPackageJsonForTheme(): void -{ - removeNpmDeps([ - 'purge', - 'dev', - 'dev:scripts', - 'build', - 'build:scripts', - ], 'scripts'); - - removeNpmDeps([ - '@awcodes/filament-plugin-purge', - 'esbuild', - 'npm-run-all', - 'prettier', - 'prettier-plugin-tailwindcss', - ], 'devDependencies'); - - replaceInFile(__DIR__ . '/package.json', [ - 'dev:styles' => 'dev', - 'build:styles' => 'build', - ]); -} - -function safeUnlink(string $filename): void -{ - if (file_exists($filename) && is_file($filename)) { - unlink($filename); - } -} - -function determineSeparator(string $path): string -{ - return str_replace('/', DIRECTORY_SEPARATOR, $path); -} - -function replaceForWindows(): array -{ - return preg_split('/\\r\\n|\\r|\\n/', run('dir /S /B * | findstr /v /i .git\ | findstr /v /i vendor | findstr /v /i ' . basename(__FILE__) . ' | findstr /r /i /M /F:/ ":author :vendor :package VendorName skeleton migration_table_name vendor_name vendor_slug author@domain.com"')); -} - -function replaceForAllOtherOSes(): array -{ - return explode(PHP_EOL, run('grep -E -r -l -i ":author|:vendor|:package|VendorName|skeleton|migration_table_name|vendor_name|vendor_slug|author@domain.com" --exclude-dir=vendor ./* ./.github/* | grep -v ' . basename(__FILE__))); -} - -function removeDirectory($dir): void -{ - if (is_dir($dir)) { - $objects = scandir($dir); - foreach ($objects as $object) { - if ($object != '.' && $object != '..') { - if (filetype($dir . '/' . $object) == 'dir') { - removeDirectory($dir . '/' . $object); - } else { - unlink($dir . '/' . $object); - } - } - } - rmdir($dir); - } -} diff --git a/database/factories/ModelFactory.php b/database/factories/ModelFactory.php index c51604f..fd416aa 100644 --- a/database/factories/ModelFactory.php +++ b/database/factories/ModelFactory.php @@ -1,6 +1,6 @@ id(); - - // add fields - - $table->timestamps(); - }); - } -}; diff --git a/package.json b/package.json index afec3c0..1e44a7e 100644 --- a/package.json +++ b/package.json @@ -2,11 +2,11 @@ "private": true, "type": "module", "scripts": { - "dev:styles": "npx tailwindcss -i resources/css/index.css -o resources/dist/skeleton.css --postcss --watch", + "dev:styles": "npx tailwindcss -i resources/css/index.css -o resources/dist/catalyst-forms-plugin.css --postcss --watch", "dev:scripts": "node bin/build.js --dev", - "build:styles": "npx tailwindcss -i resources/css/index.css -o resources/dist/skeleton.css --postcss --minify && npm run purge", + "build:styles": "npx tailwindcss -i resources/css/index.css -o resources/dist/catalyst-forms-plugin.css --postcss --minify && npm run purge", "build:scripts": "node bin/build.js", - "purge": "filament-purge -i resources/dist/skeleton.css -o resources/dist/skeleton.css -v 3.x", + "purge": "filament-purge -i resources/dist/catalyst-forms-plugin.css -o resources/dist/catalyst-forms-plugin.css -v 3.x", "dev": "npm-run-all --parallel dev:*", "build": "npm-run-all build:*" }, diff --git a/phpunit.xml.dist b/phpunit.xml.dist index e953c0e..9a0876d 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -16,7 +16,7 @@ backupStaticProperties="false" > - + tests diff --git a/resources/lang/en/skeleton.php b/resources/lang/en/skeleton.php deleted file mode 100644 index d1b24d9..0000000 --- a/resources/lang/en/skeleton.php +++ /dev/null @@ -1,6 +0,0 @@ -comment('All done'); - - return self::SUCCESS; - } -} diff --git a/src/Config/.gitkeep b/src/Config/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Config/config.php b/src/Config/config.php new file mode 100644 index 0000000..afa53c3 --- /dev/null +++ b/src/Config/config.php @@ -0,0 +1,5 @@ + 'Forms', +]; diff --git a/src/Console/.gitkeep b/src/Console/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Database/Migrations/.gitkeep b/src/Database/Migrations/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Database/Migrations/2022_09_23_195505_create_forms_table.php b/src/Database/Migrations/2022_09_23_195505_create_forms_table.php new file mode 100644 index 0000000..4b6b5f6 --- /dev/null +++ b/src/Database/Migrations/2022_09_23_195505_create_forms_table.php @@ -0,0 +1,72 @@ +id(); + $table->string('name'); + $table->string('slug'); + $table->string('type')->nullable(); + $table->json('content'); + $table->timestamps(); + }); + + Schema::create('form_types', function (Blueprint $table) { + $table->id(); + $table->string('name'); + $table->string('slug'); + $table->timestamps(); + }); + + Schema::create('forms', function (Blueprint $table) { + $table->id(); + $table->string('name'); + $table->string('slug'); + $table->json('content'); + $table->foreignIdFor(FormTemplate::class, 'form_template_id')->index()->nullable(); + $table->foreignIdFor(FormType::class, 'form_type_id')->index()->nullable(); + $table->foreignIdFor(Team::class, 'team_id')->index()->nullable(); + $table->boolean('is_used_on_all_teams')->default(false); + $table->timestamp('published_at')->nullable(); + $table->timestamps(); + }); + + Schema::create('form_submissions', function (Blueprint $table) { + $table->id(); + $table->foreignIdFor(Form::class, 'form_id')->index(); + $table->foreignIdFor(User::class, 'user_id')->index(); + $table->foreignIdFor(Team::class, 'team_id')->index()->nullable(); + $table->json('data'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('form_submissions'); + Schema::dropIfExists('forms'); + Schema::dropIfExists('form_types'); + Schema::dropIfExists('form_templates'); + } +}; diff --git a/src/Database/Migrations/2022_11_11_070610_add_for_to_form_types_table.php b/src/Database/Migrations/2022_11_11_070610_add_for_to_form_types_table.php new file mode 100644 index 0000000..62ba9c8 --- /dev/null +++ b/src/Database/Migrations/2022_11_11_070610_add_for_to_form_types_table.php @@ -0,0 +1,32 @@ +string('for')->after('slug')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('form_types', function (Blueprint $table) { + $table->dropColumn('for'); + }); + } +} diff --git a/src/Database/Migrations/2022_11_30_210219_create_form_notifications_table.php b/src/Database/Migrations/2022_11_30_210219_create_form_notifications_table.php new file mode 100644 index 0000000..a3a856f --- /dev/null +++ b/src/Database/Migrations/2022_11_30_210219_create_form_notifications_table.php @@ -0,0 +1,40 @@ +id(); + $table->foreignIdFor(Form::class, 'form_id'); + $table->foreignIdFor(Role::class, 'role_id'); + $table->string('target_role')->nullable(); + $table->string('name'); + $table->text('message')->nullable(); + $table->string('timezone')->default('UTC'); + $table->timestamp('send_date'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('form_notifications'); + } +} diff --git a/src/Database/Seeders/.gitkeep b/src/Database/Seeders/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Database/Seeders/FormsDatabaseSeeder.php b/src/Database/Seeders/FormsDatabaseSeeder.php new file mode 100644 index 0000000..407ead4 --- /dev/null +++ b/src/Database/Seeders/FormsDatabaseSeeder.php @@ -0,0 +1,43 @@ + Translate::get('Registration'), + 'slug' => 'registration', + 'for' => 'admin', + ]); + $teamResourceRequestForm = FormType::create([ + 'name' => Translate::get('Team Resource Request'), + 'slug' => 'team-resource-request', + 'for' => 'teams', + ]); + $teamMemberApplicationForm = FormType::create([ + 'name' => Translate::get('Team Member Application Form'), + 'slug' => 'team-member-application-form', + 'for' => 'teams', + ]); + $teamMemberForm = FormType::create([ + 'name' => Translate::get('Team Member Form'), + 'slug' => 'team-member-form', + 'for' => 'teams', + ]); + } +} diff --git a/src/Database/factories/.gitkeep b/src/Database/factories/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Emails/.gitkeep b/src/Emails/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Events/.gitkeep b/src/Events/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Facades/Skeleton.php b/src/Facades/Skeleton.php deleted file mode 100644 index 1fa9076..0000000 --- a/src/Facades/Skeleton.php +++ /dev/null @@ -1,16 +0,0 @@ -form->fill(); + } + + public function save(): void + { + $form = \App\Models\Form::create($this->form->getState()); + + redirect()->route('form', ['form' => $form]); + } + + public function render() + { + return view('livewire.builder'); + } + + protected function getFormSchema(): array + { + return [ + \Filament\Forms\Components\Builder::make('content') + ->blocks([ + Block::make('text') + ->label('Text input') + ->icon('heroicon-o-annotation') + ->schema([ + $this->getFieldNameInput(), + Checkbox::make('is_required'), + ]), + Block::make('select') + ->icon('heroicon-o-selector') + ->schema([ + $this->getFieldNameInput(), + KeyValue::make('options') + ->addButtonLabel('Add option') + ->keyLabel('Value') + ->valueLabel('Label'), + Checkbox::make('is_required'), + ]), + Block::make('checkbox') + ->icon('heroicon-o-check-circle') + ->schema([ + $this->getFieldNameInput(), + Checkbox::make('is_required'), + ]), + Block::make('file') + ->icon('heroicon-o-photograph') + ->schema([ + $this->getFieldNameInput(), + Grid::make() + ->schema([ + Checkbox::make('is_multiple'), + Checkbox::make('is_required'), + ]), + ]), + ]) + ->createItemButtonLabel('Add form input') + ->disableLabel(), + ]; + } + + protected function getFieldNameInput(): Grid + { + // This is not a Filament-specific method, simply saves on repetition + // between our builder blocks. + + return Grid::make() + ->schema([ + TextInput::make('name') + ->lazy() + ->afterStateUpdated(function (Closure $set, $state) { + $label = Str::of($state) + ->kebab() + ->replace(['-', '_'], ' ') + ->ucfirst(); + + $set('label', $label); + }) + ->required(), + TextInput::make('label') + ->required(), + ]); + } +} diff --git a/src/Http/Livewire/Form.php b/src/Http/Livewire/Form.php new file mode 100644 index 0000000..d87de41 --- /dev/null +++ b/src/Http/Livewire/Form.php @@ -0,0 +1,135 @@ +formModel = $form; + $this->team_id = $team_id; + $this->submitText = $submitText; + $this->form->fill(); + } + + public function submit(): void + { + $formData = $this->prepareFormData($this->form->getState()); + + $this->processFormSubmission($formData); + + $this->afterSubmission(); + } + + public function prepareFormData($formData) + { + $formModelFields = collect($this->formModel->content); + + foreach ($formData as $formDataKey => $value) { + // Search Form Model fields for the field that matches the form data + $formFieldKeyFound = $formModelFields->search(function ($formModelField, $formModelFieldKey) use ( + $formDataKey + ) { + if ($formModelField['data']['name'] === $formDataKey) { + return true; + } + }); + $formFieldType = $formModelFields[$formFieldKeyFound]['type']; + $formFieldLabel = $formModelFields[$formFieldKeyFound]['data']['label']; + $formData[$formDataKey] = [ + 'field_type' => $formFieldType, + 'data' => $value, + 'label' => $formFieldLabel, + ]; + } + + return $formData; + } + + public function processFormSubmission($formData) + { + FormSubmission::create([ + 'form_id' => $this->formModel->id, + 'user_id' => auth()->id(), + 'team_id' => $team_id ?? null, + 'data' => $formData, + ]); + } + + public function afterSubmission() + { + $this->formSubmitted = true; + + $this->success('Form submitted successfully'); + + $this->redirectRoute('social.home'); + } + + public function render() + { + return view('forms::livewire.form'); + } + + protected function getFormSchema(): array + { + return array_map(function (array $field) { + $config = $field['data']; + + $helperText = isset($config['helper_text']) ? "

{$config['helper_text']} TextInput::make($config['name']) + ->label($config['label']) + ->required($config['is_required']) + ->helperText($helperText) + ->hint($config['hint'] ?? null) + ->type($config['type']), + 'select' => Select::make($config['name']) + ->label($config['label']) + ->options($config['options']) + ->required($config['is_required']) + ->helperText($helperText) + ->hint($config['hint'] ?? null), + 'checkbox' => Checkbox::make($config['name']) + ->label($config['label']) + ->required($config['is_required']) + ->helperText($helperText) + ->hint($config['hint'] ?? null), + 'file' => FileUpload::make($config['name']) + ->label($config['label']) + ->multiple($config['is_multiple']) + ->required($config['is_required']) + ->helperText($helperText) + ->hint($config['hint'] ?? null), + }; + }, $this->formModel->content); + } + + protected function getFormStatePath(): ?string + { + // All of the form data needs to be saved in the `data` property, + // as the form is dynamic and we can't add a public property for + // every field. + return 'data'; + } +} diff --git a/src/Http/Livewire/TeamApplicationForm.php b/src/Http/Livewire/TeamApplicationForm.php new file mode 100644 index 0000000..105b80f --- /dev/null +++ b/src/Http/Livewire/TeamApplicationForm.php @@ -0,0 +1,52 @@ +team = Team::find($team_id); + + parent::mount($form, $team_id, $submitText); + + $this->applicationForm = $form; + } + + public function processFormSubmission($formData) + { + $this->applyToTeam(); + + $application = TeamApplication::query() + ->where('user_id', $this->user->id) + ->where('team_id', $this->team_id) + ->first(); + + $formSubmission = FormSubmission::create([ + 'form_id' => $this->formModel->id, + 'user_id' => $this->user->id, + 'team_id' => $this->team_id ?? null, + 'data' => $formData, + ]); + + $application->update(['form_submission_id' => $formSubmission->id]); + } + + public function afterSubmission() + { + $this->redirectRoute('social.teams.show', $this->team); + } +} diff --git a/src/Http/Livewire/UserRegistrationForm.php b/src/Http/Livewire/UserRegistrationForm.php new file mode 100644 index 0000000..c704407 --- /dev/null +++ b/src/Http/Livewire/UserRegistrationForm.php @@ -0,0 +1,90 @@ + [ + 'hint' => null, + 'name' => 'first_name', + 'type' => 'text', + 'label' => 'First name', + 'helper_text' => null, + 'is_required' => true, + ], + 'type' => 'text', + ], + [ + 'data' => [ + 'hint' => null, + 'name' => 'last_name', + 'type' => 'text', + 'label' => 'Last name', + 'helper_text' => null, + 'is_required' => true, + ], + 'type' => 'text', + ], + [ + 'data' => [ + 'hint' => null, + 'name' => 'email', + 'type' => 'email', + 'label' => 'Email', + 'helper_text' => null, + 'is_required' => true, + ], + 'type' => 'text', + ], + [ + 'data' => [ + 'hint' => null, + 'name' => 'password', + 'type' => 'password', + 'label' => 'Password', + 'helper_text' => null, + 'is_required' => true, + ], + 'type' => 'text', + ], + [ + 'data' => [ + 'hint' => null, + 'name' => 'password_confirmation', + 'type' => 'password', + 'label' => 'Password confirmation', + 'helper_text' => null, + 'is_required' => true, + ], + 'type' => 'text', + ], + ]; + } + + public function processFormSubmission($formData) + { + $registrationData = array_map(fn ($item): string => $item['data'], $formData); + + event(new Registered($user = (new CreateNewUser)->create($registrationData))); + auth()->login($user); + + unset($formData['password']); + unset($formData['password_confirmation']); + + FormSubmission::create([ + 'form_id' => $this->formModel->id, + 'user_id' => $user->id, + 'team_id' => $this->team_id ?? null, + 'data' => $formData, + ]); + } +} diff --git a/src/Http/Middleware/.gitkeep b/src/Http/Middleware/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Http/Requests/.gitkeep b/src/Http/Requests/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Jobs/.gitkeep b/src/Jobs/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Jobs/SendFormNotificationsJob.php b/src/Jobs/SendFormNotificationsJob.php new file mode 100644 index 0000000..c27b7f4 --- /dev/null +++ b/src/Jobs/SendFormNotificationsJob.php @@ -0,0 +1,72 @@ +whereMidnight())->each(function ($date, $tz) { + FormNotification::whereDate('send_date', $date) + ->where('timezone', $tz) + ->each(fn ($formNotification) => $this->send($formNotification)); + }); + } + + /** + * Get the name of the timezones (if any) where it is currently midnight. + * + * @return string + */ + private function whereMidnight() + { + return collect(CarbonTimeZone::listIdentifiers()) + ->filter(function ($name) { + return Carbon::now($name)->setSeconds(0)->isMidnight(); + })->flatMap(function ($tz) { + return [$tz => Carbon::now($tz)->startOfDay()->toDateTimeString()]; + }); + } + + /** + * Send the given formNotification to required users. + * + * @return void + */ + private function send(FormNotification $formNotification) + { + $team = Team::findOrFail($formNotification->form->team_id); + + $team->members()->where('role', $formNotification->role->name) + ->each(function ($user) use ($team, $formNotification) { + $user->notify(new FormReminderNotification($team, $formNotification)); + }); + } +} diff --git a/src/Listeners/.gitkeep b/src/Listeners/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Models/.gitkeep b/src/Models/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Models/Form.php b/src/Models/Form.php new file mode 100644 index 0000000..c87d11b --- /dev/null +++ b/src/Models/Form.php @@ -0,0 +1,64 @@ + 'array', + ]; + + protected $guarded = []; + + public static function getRegistrationForm() + { + return self::query() + ->where('form_type_id', FormType::userRegistrationFormId()) + ->whereNotNull('form_type_id') + ->first(); + } + + public function getSlugOptions(): SlugOptions + { + return SlugOptions::create() + ->generateSlugsFrom('name') + ->saveSlugsTo('slug') + ->doNotGenerateSlugsOnUpdate(); + } + + // Attributes + + public function getIsActiveAttribute() + { + return ! is_null($this->published_at); + } + + // Relationships + + public function formTemplate() + { + return $this->belongsTo(FormTemplate::class); + } + + public function notifications() + { + return $this->hasMany(FormNotification::class); + } + + public function submissions() + { + return $this->hasMany(FormSubmission::class); + } + + public function formType() + { + return $this->belongsTo(FormType::class); + } +} diff --git a/src/Models/FormNotification.php b/src/Models/FormNotification.php new file mode 100644 index 0000000..00e58ab --- /dev/null +++ b/src/Models/FormNotification.php @@ -0,0 +1,54 @@ +send_date)->format('m/d/y'); + } + + public function getSendDateEditAttribute() + { + return Carbon::parse($this->send_date); + } + + public function setSendDateEditAttribute($value) + { + $this->send_date = Carbon::parse($value); + } + + // Relationships + + public function form() + { + return $this->belongsTo(Form::class); + } + + public function role() + { + return $this->belongsTo(Role::class); + } + + public function scheduledNotification() + { + return $this->belongsTo(ScheduledNotification::class); + } +} diff --git a/src/Models/FormSubmission.php b/src/Models/FormSubmission.php new file mode 100644 index 0000000..f055ca7 --- /dev/null +++ b/src/Models/FormSubmission.php @@ -0,0 +1,45 @@ + 'array', + ]; + + public function form() + { + return $this->belongsTo(Form::class); + } + + public function team() + { + return $this->belongsTo(Team::class); + } + + public function user() + { + return $this->belongsTo(User::class); + } + + public function teamApplication() + { + return $this->hasOne(TeamApplication::class); + } +} diff --git a/src/Models/FormTemplate.php b/src/Models/FormTemplate.php new file mode 100644 index 0000000..6855ca8 --- /dev/null +++ b/src/Models/FormTemplate.php @@ -0,0 +1,37 @@ + 'array', + ]; + + protected $guarded = []; + + public function getSlugOptions(): SlugOptions + { + return SlugOptions::create() + ->generateSlugsFrom('name') + ->saveSlugsTo('slug') + ->doNotGenerateSlugsOnUpdate(); + } + + public function forms() + { + return $this->hasMany(Form::class); + } +} diff --git a/src/Models/FormType.php b/src/Models/FormType.php new file mode 100644 index 0000000..a8fcbd2 --- /dev/null +++ b/src/Models/FormType.php @@ -0,0 +1,59 @@ +get(); + } + + public static function teamApplicationFormId() + { + return self::teamApplicationForm()?->id; + } + + public static function teamApplicationForm() + { + return self::where('slug', 'team-member-application-form')->first(); + } + + public static function userRegistrationFormId() + { + return self::userRegistrationForm()?->id; + } + + public static function userRegistrationForm() + { + return self::where('slug', 'registration')->first(); + } + + public function getSlugOptions(): SlugOptions + { + return SlugOptions::create() + ->generateSlugsFrom('name') + ->saveSlugsTo('slug') + ->doNotGenerateSlugsOnUpdate(); + } + + // Relationships + + public function forms() + { + return $this->hasMany(Form::class); + } +} diff --git a/src/Notifications/.gitkeep b/src/Notifications/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Notifications/FormReminderNotification.php b/src/Notifications/FormReminderNotification.php new file mode 100644 index 0000000..b16bda4 --- /dev/null +++ b/src/Notifications/FormReminderNotification.php @@ -0,0 +1,78 @@ +hasTeamRole($this->team, $this->formNotification->role->name)) { + return ['broadcast', 'database', 'mail']; + } + } + + /** + * Get the mail representation of the notification. + * + * @param mixed $notifiable + * @return MailMessage + */ + public function toMail($notifiable) + { + return (new MailMessage) + ->subject('Reminder: ' . Translate::get($this->formNotification->name)) + ->greeting(Translate::get($this->formNotification->name)) + ->line(Translate::get($this->formNotification->message)) + ->line('Team: ' . $this->team->name) + ->line('Form: ' . $this->formNotification->form->name) + ->action('Go to Team Page', route('social.teams.show', $this->team)) + ->line('Thank you!'); + } + + /** + * Get the array representation of the notification. + * + * @param mixed $notifiable + * @return array + */ + public function toArray($notifiable) + { + $url = route('social.teams.show', $this->team); + + return NotificationCenter::make() + ->icon('heroicon-o-clock') + ->info(Translate::get($this->formNotification->name)) + ->subtitle(Translate::get($this->formNotification->message)) + ->image($this->team->profile_photo_url) + ->actionLink($url) + ->actionText('Go to Team Page') + ->toArray(); + } +} diff --git a/src/Policies/.gitkeep b/src/Policies/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Policies/FormPolicy.php b/src/Policies/FormPolicy.php new file mode 100644 index 0000000..fdc0389 --- /dev/null +++ b/src/Policies/FormPolicy.php @@ -0,0 +1,108 @@ +can('view_any_form'); + } + + /** + * Determine whether the user can view the model. + */ + public function view(User $user, Form $form): bool + { + return $user->can('view_form'); + } + + /** + * Determine whether the user can create models. + */ + public function create(User $user): bool + { + return $user->can('create_form'); + } + + /** + * Determine whether the user can update the model. + */ + public function update(User $user, Form $form): bool + { + return $user->can('update_form'); + } + + /** + * Determine whether the user can delete the model. + */ + public function delete(User $user, Form $form): bool + { + return $user->can('delete_form'); + } + + /** + * Determine whether the user can bulk delete. + */ + public function deleteAny(User $user): bool + { + return $user->can('delete_any_form'); + } + + /** + * Determine whether the user can permanently delete. + */ + public function forceDelete(User $user, Form $form): bool + { + return $user->can('force_delete_form'); + } + + /** + * Determine whether the user can permanently bulk delete. + */ + public function forceDeleteAny(User $user): bool + { + return $user->can('force_delete_any_form'); + } + + /** + * Determine whether the user can restore. + */ + public function restore(User $user, Form $form): bool + { + return $user->can('restore_form'); + } + + /** + * Determine whether the user can bulk restore. + */ + public function restoreAny(User $user): bool + { + return $user->can('restore_any_form'); + } + + /** + * Determine whether the user can replicate. + */ + public function replicate(User $user, Form $form): bool + { + return $user->can('replicate_form'); + } + + /** + * Determine whether the user can reorder. + */ + public function reorder(User $user): bool + { + return $user->can('reorder_form'); + } +} diff --git a/src/Policies/FormSubmissionPolicy.php b/src/Policies/FormSubmissionPolicy.php new file mode 100644 index 0000000..b015110 --- /dev/null +++ b/src/Policies/FormSubmissionPolicy.php @@ -0,0 +1,108 @@ +can('view_any_form::submission'); + } + + /** + * Determine whether the user can view the model. + */ + public function view(User $user, FormSubmission $formSubmission): bool + { + return $user->can('view_form::submission'); + } + + /** + * Determine whether the user can create models. + */ + public function create(User $user): bool + { + return $user->can('create_form::submission'); + } + + /** + * Determine whether the user can update the model. + */ + public function update(User $user, FormSubmission $formSubmission): bool + { + return $user->can('update_form::submission'); + } + + /** + * Determine whether the user can delete the model. + */ + public function delete(User $user, FormSubmission $formSubmission): bool + { + return $user->can('delete_form::submission'); + } + + /** + * Determine whether the user can bulk delete. + */ + public function deleteAny(User $user): bool + { + return $user->can('delete_any_form::submission'); + } + + /** + * Determine whether the user can permanently delete. + */ + public function forceDelete(User $user, FormSubmission $formSubmission): bool + { + return $user->can('force_delete_form::submission'); + } + + /** + * Determine whether the user can permanently bulk delete. + */ + public function forceDeleteAny(User $user): bool + { + return $user->can('force_delete_any_form::submission'); + } + + /** + * Determine whether the user can restore. + */ + public function restore(User $user, FormSubmission $formSubmission): bool + { + return $user->can('restore_form::submission'); + } + + /** + * Determine whether the user can bulk restore. + */ + public function restoreAny(User $user): bool + { + return $user->can('restore_any_form::submission'); + } + + /** + * Determine whether the user can replicate. + */ + public function replicate(User $user, FormSubmission $formSubmission): bool + { + return $user->can('replicate_form::submission'); + } + + /** + * Determine whether the user can reorder. + */ + public function reorder(User $user): bool + { + return $user->can('reorder_form::submission'); + } +} diff --git a/src/Policies/FormTypePolicy.php b/src/Policies/FormTypePolicy.php new file mode 100644 index 0000000..71b8679 --- /dev/null +++ b/src/Policies/FormTypePolicy.php @@ -0,0 +1,108 @@ +can('view_any_form::type'); + } + + /** + * Determine whether the user can view the model. + */ + public function view(User $user, FormType $formType): bool + { + return $user->can('view_form::type'); + } + + /** + * Determine whether the user can create models. + */ + public function create(User $user): bool + { + return $user->can('create_form::type'); + } + + /** + * Determine whether the user can update the model. + */ + public function update(User $user, FormType $formType): bool + { + return $user->can('update_form::type'); + } + + /** + * Determine whether the user can delete the model. + */ + public function delete(User $user, FormType $formType): bool + { + return $user->can('delete_form::type'); + } + + /** + * Determine whether the user can bulk delete. + */ + public function deleteAny(User $user): bool + { + return $user->can('delete_any_form::type'); + } + + /** + * Determine whether the user can permanently delete. + */ + public function forceDelete(User $user, FormType $formType): bool + { + return $user->can('force_delete_form::type'); + } + + /** + * Determine whether the user can permanently bulk delete. + */ + public function forceDeleteAny(User $user): bool + { + return $user->can('force_delete_any_form::type'); + } + + /** + * Determine whether the user can restore. + */ + public function restore(User $user, FormType $formType): bool + { + return $user->can('restore_form::type'); + } + + /** + * Determine whether the user can bulk restore. + */ + public function restoreAny(User $user): bool + { + return $user->can('restore_any_form::type'); + } + + /** + * Determine whether the user can replicate. + */ + public function replicate(User $user, FormType $formType): bool + { + return $user->can('replicate_form::type'); + } + + /** + * Determine whether the user can reorder. + */ + public function reorder(User $user): bool + { + return $user->can('reorder_form::type'); + } +} diff --git a/src/Providers/.gitkeep b/src/Providers/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Providers/FormsServiceProvider.php b/src/Providers/FormsServiceProvider.php new file mode 100644 index 0000000..ed296fb --- /dev/null +++ b/src/Providers/FormsServiceProvider.php @@ -0,0 +1,113 @@ +registerTranslations(); + $this->registerConfig(); + $this->registerViews(); + $this->loadMigrationsFrom(module_path($this->moduleName, 'Database/Migrations')); + } + + /** + * Register translations. + * + * @return void + */ + public function registerTranslations() + { + $langPath = resource_path('lang/modules/' . $this->moduleNameLower); + + if (is_dir($langPath)) { + $this->loadTranslationsFrom($langPath, $this->moduleNameLower); + } else { + $this->loadTranslationsFrom(module_path($this->moduleName, 'Resources/lang'), $this->moduleNameLower); + } + } + + /** + * Register views. + * + * @return void + */ + public function registerViews() + { + $viewPath = resource_path('views/modules/' . $this->moduleNameLower); + + $sourcePath = module_path($this->moduleName, 'Resources/views'); + + $this->publishes([ + $sourcePath => $viewPath, + ], ['views', $this->moduleNameLower . '-module-views']); + + $this->loadViewsFrom(array_merge($this->getPublishableViewPaths(), [$sourcePath]), $this->moduleNameLower); + } + + /** + * Register the service provider. + * + * @return void + */ + public function register() + { + $this->app->register(RouteServiceProvider::class); + } + + /** + * Get the services provided by the provider. + * + * @return array + */ + public function provides() + { + return []; + } + + /** + * Register config. + * + * @return void + */ + protected function registerConfig() + { + $this->publishes([ + module_path($this->moduleName, 'Config/config.php') => config_path($this->moduleNameLower . '.php'), + ], 'config'); + $this->mergeConfigFrom( + module_path($this->moduleName, 'Config/config.php'), $this->moduleNameLower + ); + } + + private function getPublishableViewPaths(): array + { + $paths = []; + foreach (Config::get('view.paths') as $path) { + if (is_dir($path . '/modules/' . $this->moduleNameLower)) { + $paths[] = $path . '/modules/' . $this->moduleNameLower; + } + } + + return $paths; + } +} diff --git a/src/Providers/RouteServiceProvider.php b/src/Providers/RouteServiceProvider.php new file mode 100644 index 0000000..8e21538 --- /dev/null +++ b/src/Providers/RouteServiceProvider.php @@ -0,0 +1,69 @@ +mapApiRoutes(); + + $this->mapWebRoutes(); + } + + /** + * Define the "api" routes for the application. + * + * These routes are typically stateless. + * + * @return void + */ + protected function mapApiRoutes() + { + Route::prefix('api') + ->middleware('api') + ->namespace($this->moduleNamespace) + ->group(module_path('Forms', '/Routes/api.php')); + } + + /** + * Define the "web" routes for the application. + * + * These routes all receive session state, CSRF protection, etc. + * + * @return void + */ + protected function mapWebRoutes() + { + Route::middleware('web') + ->namespace($this->moduleNamespace) + ->group(module_path('Forms', '/Routes/web.php')); + } +} diff --git a/src/Repositories/.gitkeep b/src/Repositories/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Resources/assets/.gitkeep b/src/Resources/assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Resources/assets/js/app.js b/src/Resources/assets/js/app.js new file mode 100644 index 0000000..e69de29 diff --git a/src/Resources/assets/sass/app.scss b/src/Resources/assets/sass/app.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/Resources/lang/.gitkeep b/src/Resources/lang/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Resources/views/.gitkeep b/src/Resources/views/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Resources/views/components/.gitkeep b/src/Resources/views/components/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Resources/views/index.blade.php b/src/Resources/views/index.blade.php new file mode 100644 index 0000000..4b54d20 --- /dev/null +++ b/src/Resources/views/index.blade.php @@ -0,0 +1,9 @@ +@extends('forms::layouts.master') + +@section('content') + Hello World + +

+ This view is loaded from module: {!! config('forms.name') !!} +

+@endsection diff --git a/src/Resources/views/layouts/master.blade.php b/src/Resources/views/layouts/master.blade.php new file mode 100644 index 0000000..135ff85 --- /dev/null +++ b/src/Resources/views/layouts/master.blade.php @@ -0,0 +1,19 @@ + + + + + + + Module Forms + + {{-- Laravel Mix - CSS File --}} + {{-- --}} + + + +@yield('content') + +{{-- Laravel Mix - JS File --}} +{{-- --}} + + diff --git a/src/Resources/views/livewire/builder.blade.php b/src/Resources/views/livewire/builder.blade.php new file mode 100644 index 0000000..b9ec7d3 --- /dev/null +++ b/src/Resources/views/livewire/builder.blade.php @@ -0,0 +1,11 @@ +
+
+
+ {{ $this->form }} +
+ + + Save & preview + +
+
diff --git a/src/Resources/views/livewire/form-submission.blade.php b/src/Resources/views/livewire/form-submission.blade.php new file mode 100644 index 0000000..d10644e --- /dev/null +++ b/src/Resources/views/livewire/form-submission.blade.php @@ -0,0 +1,5 @@ +
+
+ {{ $this->data }} +
+
diff --git a/src/Resources/views/livewire/form.blade.php b/src/Resources/views/livewire/form.blade.php new file mode 100644 index 0000000..0e11d7f --- /dev/null +++ b/src/Resources/views/livewire/form.blade.php @@ -0,0 +1,21 @@ +
+
+ @unless ($formSubmitted) +
+ {{ $this->form }} +
+ + + {{ $submitText }} + Processing... + + @else +
+

{{ Translate::get('Your form was submitted successfully.') }}

+
+ @endunless +
+
diff --git a/src/Routes/.gitkeep b/src/Routes/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Routes/api.php b/src/Routes/api.php new file mode 100644 index 0000000..1e723e9 --- /dev/null +++ b/src/Routes/api.php @@ -0,0 +1,18 @@ +get('/forms', function (Request $request) { + return $request->user(); +}); diff --git a/src/Routes/web.php b/src/Routes/web.php new file mode 100644 index 0000000..61f36d9 --- /dev/null +++ b/src/Routes/web.php @@ -0,0 +1,18 @@ +prefix('forms')->group(function () { + Route::get('/forms/{form}', Form::class)->name('form'); +}); diff --git a/src/Rules/.gitkeep b/src/Rules/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/Skeleton.php b/src/Skeleton.php deleted file mode 100644 index 66fab60..0000000 --- a/src/Skeleton.php +++ /dev/null @@ -1,7 +0,0 @@ -getId()); - - return $plugin; - } -} diff --git a/src/SkeletonServiceProvider.php b/src/SkeletonServiceProvider.php deleted file mode 100644 index 266d50d..0000000 --- a/src/SkeletonServiceProvider.php +++ /dev/null @@ -1,154 +0,0 @@ -name(static::$name) - ->hasCommands($this->getCommands()) - ->hasInstallCommand(function (InstallCommand $command) { - $command - ->publishConfigFile() - ->publishMigrations() - ->askToRunMigrations() - ->askToStarRepoOnGitHub(':vendor_slug/:package_slug'); - }); - - $configFileName = $package->shortName(); - - if (file_exists($package->basePath("/../config/{$configFileName}.php"))) { - $package->hasConfigFile(); - } - - if (file_exists($package->basePath('/../database/migrations'))) { - $package->hasMigrations($this->getMigrations()); - } - - if (file_exists($package->basePath('/../resources/lang'))) { - $package->hasTranslations(); - } - - if (file_exists($package->basePath('/../resources/views'))) { - $package->hasViews(static::$viewNamespace); - } - } - - public function packageRegistered(): void - { - } - - public function packageBooted(): void - { - // Asset Registration - FilamentAsset::register( - $this->getAssets(), - $this->getAssetPackageName() - ); - - FilamentAsset::registerScriptData( - $this->getScriptData(), - $this->getAssetPackageName() - ); - - // Icon Registration - FilamentIcon::register($this->getIcons()); - - // Handle Stubs - if (app()->runningInConsole()) { - foreach (app(Filesystem::class)->files(__DIR__ . '/../stubs/') as $file) { - $this->publishes([ - $file->getRealPath() => base_path("stubs/skeleton/{$file->getFilename()}"), - ], 'skeleton-stubs'); - } - } - - // Testing - Testable::mixin(new TestsSkeleton()); - } - - protected function getAssetPackageName(): ?string - { - return ':vendor_slug/:package_slug'; - } - - /** - * @return array - */ - protected function getAssets(): array - { - return [ - // AlpineComponent::make('skeleton', __DIR__ . '/../resources/dist/components/skeleton.js'), - Css::make('skeleton-styles', __DIR__ . '/../resources/dist/skeleton.css'), - Js::make('skeleton-scripts', __DIR__ . '/../resources/dist/skeleton.js'), - ]; - } - - /** - * @return array - */ - protected function getCommands(): array - { - return [ - SkeletonCommand::class, - ]; - } - - /** - * @return array - */ - protected function getIcons(): array - { - return []; - } - - /** - * @return array - */ - protected function getRoutes(): array - { - return []; - } - - /** - * @return array - */ - protected function getScriptData(): array - { - return []; - } - - /** - * @return array - */ - protected function getMigrations(): array - { - return [ - 'create_skeleton_table', - ]; - } -} diff --git a/src/SkeletonTheme.php b/src/SkeletonTheme.php deleted file mode 100644 index 6c647e0..0000000 --- a/src/SkeletonTheme.php +++ /dev/null @@ -1,39 +0,0 @@ -font('DM Sans') - ->primaryColor(Color::Amber) - ->secondaryColor(Color::Gray) - ->warningColor(Color::Amber) - ->dangerColor(Color::Rose) - ->successColor(Color::Green) - ->grayColor(Color::Gray) - ->theme('skeleton'); - } - - public function boot(Panel $panel): void - { - // - } -} diff --git a/src/Testing/TestsSkeleton.php b/src/Testing/TestsSkeleton.php deleted file mode 100644 index 0e33b51..0000000 --- a/src/Testing/TestsSkeleton.php +++ /dev/null @@ -1,13 +0,0 @@ -form->getState(); + + $formData = [ + 'name' => $form['name'], + 'slug' => $form['slug'], + 'form_type_id' => $form['form_type_id'], + 'team_id' => $teamId, + 'content' => $form['content'], + ]; + + if ($this->formModel) { + $this->formModel->update($formData); + } else { + Form::create($formData); + } + + $this->success(Translate::get('Form created successfully')); + + if ($teamId) { + $this->redirectRoute('social.teams.admin', Team::find($teamId)); + } else { + $this->redirectRoute('social.home'); + } + } + + protected function getFormSchema(): array + { + return [ + TextInput::make('name') + ->label('Name') + ->required(true), + Select::make('form_type_id') + ->label('Form Type') + ->options(FormType::forTeams()->pluck('name', 'id')->toArray()), + TextInput::make('slug') + ->label('Slug') + ->required(true) + ->hint("

Once created, you cannot change this value.

") + ->columnSpan(2), + Builder::make('content') + ->columnSpan(2) + ->blocks([ + Block::make('text') + ->label('Text input') + ->icon('heroicon-o-annotation') + ->schema([ + $this->getFieldNameInput(), + Select::make('type') + ->options([ + 'email' => 'Email', + 'password' => 'Password', + 'text' => 'Text', + ]) + ->default('text') + ->disablePlaceholderSelection() + ->required(), + Checkbox::make('is_required'), + ]), + Block::make('select') + ->icon('heroicon-o-selector') + ->schema([ + $this->getFieldNameInput(), + KeyValue::make('options') + ->addButtonLabel('Add option') + ->keyLabel('Value') + ->valueLabel('Label'), + Checkbox::make('is_required'), + ]), + Block::make('checkbox') + ->icon('heroicon-o-check-circle') + ->schema([ + $this->getFieldNameInput(), + Checkbox::make('is_required'), + ]), + Block::make('file') + ->icon('heroicon-o-photograph') + ->schema([ + $this->getFieldNameInput(), + Grid::make() + ->schema([ + Checkbox::make('is_multiple'), + Checkbox::make('is_required'), + ]), + ]), + ]) + ->createItemButtonLabel('Add Form Element') + ->disableLabel(), + ]; + } + + protected function getFieldNameInput(): Grid + { + // This is not a Filament-specific method, simply saves on repetition + // between our builder blocks. + return Grid::make() + ->schema([ + TextInput::make('label') + ->columnSpan(2) + ->lazy() + ->afterStateUpdated(function (Closure $set, $state) { + $name = Str::of($state) + ->snake() + ->lower() . uniqid('_'); + $set('name', $name); + }) + ->required(), + TextInput::make('name') + ->hidden() + ->required(), + + ]); + } +} diff --git a/src/Traits/Livewire/WithFormManagement.php b/src/Traits/Livewire/WithFormManagement.php new file mode 100644 index 0000000..43ba71e --- /dev/null +++ b/src/Traits/Livewire/WithFormManagement.php @@ -0,0 +1,88 @@ +confirmingPublishform = true; + + $this->formIdBeingPublished = $formId; + + $this->newStatus = $status; + } + + public function changeFormStatus() + { + $form = Form::find($this->formIdBeingPublished); + + if ($form->isActive) { + $form->update(['published_at' => null]); + + $this->dispatch('formSavedAsDraft'); + } else { + $form->update(['published_at' => now()]); + + $this->dispatch('formPublished'); + } + + $this->confirmingPublishform = false; + + $this->formIdBeingPublished = null; + + $this->newStatus = ''; + } + + public function confirmFormRemoval($formId) + { + $this->confirmingFormRemoval = true; + + $this->formIdBeingRemoved = $formId; + } + + public function removeForm() + { + Form::find($this->formIdBeingRemoved)->delete(); + + $this->confirmingFormRemoval = false; + + $this->formIdBeingRemoved = null; + + $this->dispatch('formRemoved'); + } + + public function confirmFormNotificationRemoval($formNotificationId) + { + $this->confirmingFormNotificationRemoval = true; + + $this->formNotificationIdBeingRemoved = $formNotificationId; + } + + public function removeFormNotification() + { + FormNotification::find($this->formNotificationIdBeingRemoved)->delete(); + + $this->confirmingFormNotificationRemoval = false; + + $this->formNotificationIdBeingRemoved = null; + + $this->dispatch('formNotificationRemoved'); + } +} diff --git a/src/Transformers/.gitkeep b/src/Transformers/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/View/Component/.gitkeep b/src/View/Component/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/tests/Pest.php b/tests/Pest.php index 7fe1500..e73fab1 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -1,5 +1,5 @@ in(__DIR__); diff --git a/tests/TestCase.php b/tests/TestCase.php index 8ef205d..1a1e800 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -1,6 +1,6 @@ 'VendorName\\Skeleton\\Database\\Factories\\' . class_basename($modelName) . 'Factory' + fn (string $modelName) => 'OmniaDigital\\CatalystFormsPlugin\\Database\\Factories\\' . class_basename($modelName) . 'Factory' ); } @@ -48,7 +48,7 @@ protected function getPackageProviders($app) SupportServiceProvider::class, TablesServiceProvider::class, WidgetsServiceProvider::class, - SkeletonServiceProvider::class, + CatalystFormsPluginServiceProvider::class, ]; } @@ -57,7 +57,7 @@ public function getEnvironmentSetUp($app) config()->set('database.default', 'testing'); /* - $migration = include __DIR__.'/../database/migrations/create_skeleton_table.php.stub'; + $migration = include __DIR__.'/../database/migrations/create_catalyst-forms-plugin_table.php.stub'; $migration->up(); */ } From caf5a6f15ee95fbfda13e899b74625e2837d51cb Mon Sep 17 00:00:00 2001 From: Josh Torres Date: Wed, 4 Oct 2023 16:15:23 -0700 Subject: [PATCH 2/4] - add initial config - add files from forms module --- config/catalyst-forms-plugin.php | 6 + ...reate_catalyst_forms_plugin_table.php.stub | 19 +++ resources/lang/en/catalyst-forms-plugin.php | 6 + src/CatalystFormsPlugin.php | 7 + src/CatalystFormsPluginPlugin.php | 37 +++++ src/CatalystFormsPluginServiceProvider.php | 154 ++++++++++++++++++ src/Commands/CatalystFormsPluginCommand.php | 19 +++ src/Facades/CatalystFormsPlugin.php | 16 ++ src/Testing/TestsCatalystFormsPlugin.php | 13 ++ 9 files changed, 277 insertions(+) create mode 100644 config/catalyst-forms-plugin.php create mode 100644 database/migrations/create_catalyst_forms_plugin_table.php.stub create mode 100644 resources/lang/en/catalyst-forms-plugin.php create mode 100644 src/CatalystFormsPlugin.php create mode 100644 src/CatalystFormsPluginPlugin.php create mode 100644 src/CatalystFormsPluginServiceProvider.php create mode 100644 src/Commands/CatalystFormsPluginCommand.php create mode 100644 src/Facades/CatalystFormsPlugin.php create mode 100644 src/Testing/TestsCatalystFormsPlugin.php diff --git a/config/catalyst-forms-plugin.php b/config/catalyst-forms-plugin.php new file mode 100644 index 0000000..c1a8e7a --- /dev/null +++ b/config/catalyst-forms-plugin.php @@ -0,0 +1,6 @@ +id(); + + // add fields + + $table->timestamps(); + }); + } +}; diff --git a/resources/lang/en/catalyst-forms-plugin.php b/resources/lang/en/catalyst-forms-plugin.php new file mode 100644 index 0000000..f207df2 --- /dev/null +++ b/resources/lang/en/catalyst-forms-plugin.php @@ -0,0 +1,6 @@ +getId()); + + return $plugin; + } +} diff --git a/src/CatalystFormsPluginServiceProvider.php b/src/CatalystFormsPluginServiceProvider.php new file mode 100644 index 0000000..a27bd02 --- /dev/null +++ b/src/CatalystFormsPluginServiceProvider.php @@ -0,0 +1,154 @@ +name(static::$name) + ->hasCommands($this->getCommands()) + ->hasInstallCommand(function (InstallCommand $command) { + $command + ->publishConfigFile() + ->publishMigrations() + ->askToRunMigrations() + ->askToStarRepoOnGitHub('omnia-digital/catalyst-forms-plugin'); + }); + + $configFileName = $package->shortName(); + + if (file_exists($package->basePath("/../config/{$configFileName}.php"))) { + $package->hasConfigFile(); + } + + if (file_exists($package->basePath('/../database/migrations'))) { + $package->hasMigrations($this->getMigrations()); + } + + if (file_exists($package->basePath('/../resources/lang'))) { + $package->hasTranslations(); + } + + if (file_exists($package->basePath('/../resources/views'))) { + $package->hasViews(static::$viewNamespace); + } + } + + public function packageRegistered(): void + { + } + + public function packageBooted(): void + { + // Asset Registration + FilamentAsset::register( + $this->getAssets(), + $this->getAssetPackageName() + ); + + FilamentAsset::registerScriptData( + $this->getScriptData(), + $this->getAssetPackageName() + ); + + // Icon Registration + FilamentIcon::register($this->getIcons()); + + // Handle Stubs + if (app()->runningInConsole()) { + foreach (app(Filesystem::class)->files(__DIR__ . '/../stubs/') as $file) { + $this->publishes([ + $file->getRealPath() => base_path("stubs/catalyst-forms-plugin/{$file->getFilename()}"), + ], 'catalyst-forms-plugin-stubs'); + } + } + + // Testing + Testable::mixin(new TestsCatalystFormsPlugin()); + } + + protected function getAssetPackageName(): ?string + { + return 'omnia-digital/catalyst-forms-plugin'; + } + + /** + * @return array + */ + protected function getAssets(): array + { + return [ + // AlpineComponent::make('catalyst-forms-plugin', __DIR__ . '/../resources/dist/components/catalyst-forms-plugin.js'), + Css::make('catalyst-forms-plugin-styles', __DIR__ . '/../resources/dist/catalyst-forms-plugin.css'), + Js::make('catalyst-forms-plugin-scripts', __DIR__ . '/../resources/dist/catalyst-forms-plugin.js'), + ]; + } + + /** + * @return array + */ + protected function getCommands(): array + { + return [ + CatalystFormsPluginCommand::class, + ]; + } + + /** + * @return array + */ + protected function getIcons(): array + { + return []; + } + + /** + * @return array + */ + protected function getRoutes(): array + { + return []; + } + + /** + * @return array + */ + protected function getScriptData(): array + { + return []; + } + + /** + * @return array + */ + protected function getMigrations(): array + { + return [ + 'create_catalyst-forms-plugin_table', + ]; + } +} diff --git a/src/Commands/CatalystFormsPluginCommand.php b/src/Commands/CatalystFormsPluginCommand.php new file mode 100644 index 0000000..4e0c422 --- /dev/null +++ b/src/Commands/CatalystFormsPluginCommand.php @@ -0,0 +1,19 @@ +comment('All done'); + + return self::SUCCESS; + } +} diff --git a/src/Facades/CatalystFormsPlugin.php b/src/Facades/CatalystFormsPlugin.php new file mode 100644 index 0000000..ea427a4 --- /dev/null +++ b/src/Facades/CatalystFormsPlugin.php @@ -0,0 +1,16 @@ + Date: Wed, 4 Oct 2023 23:15:53 +0000 Subject: [PATCH 3/4] Fix styling --- src/CatalystFormsPluginServiceProvider.php | 4 ++-- src/Http/Livewire/Form.php | 7 ++++++- src/Jobs/SendFormNotificationsJob.php | 5 ++++- src/Models/Form.php | 3 ++- src/Models/FormNotification.php | 1 + src/Models/FormTemplate.php | 3 ++- src/Models/FormType.php | 3 ++- src/Providers/FormsServiceProvider.php | 3 ++- src/Traits/Livewire/WithFormBuilder.php | 13 +++++++++---- src/Traits/Livewire/WithFormManagement.php | 4 ++++ tests/TestCase.php | 2 +- 11 files changed, 35 insertions(+), 13 deletions(-) diff --git a/src/CatalystFormsPluginServiceProvider.php b/src/CatalystFormsPluginServiceProvider.php index a27bd02..029af79 100644 --- a/src/CatalystFormsPluginServiceProvider.php +++ b/src/CatalystFormsPluginServiceProvider.php @@ -10,11 +10,11 @@ use Filament\Support\Facades\FilamentIcon; use Illuminate\Filesystem\Filesystem; use Livewire\Features\SupportTesting\Testable; +use OmniaDigital\CatalystFormsPlugin\Commands\CatalystFormsPluginCommand; +use OmniaDigital\CatalystFormsPlugin\Testing\TestsCatalystFormsPlugin; use Spatie\LaravelPackageTools\Commands\InstallCommand; use Spatie\LaravelPackageTools\Package; use Spatie\LaravelPackageTools\PackageServiceProvider; -use OmniaDigital\CatalystFormsPlugin\Commands\CatalystFormsPluginCommand; -use OmniaDigital\CatalystFormsPlugin\Testing\TestsCatalystFormsPlugin; class CatalystFormsPluginServiceProvider extends PackageServiceProvider { diff --git a/src/Http/Livewire/Form.php b/src/Http/Livewire/Form.php index d87de41..a7e489c 100644 --- a/src/Http/Livewire/Form.php +++ b/src/Http/Livewire/Form.php @@ -14,14 +14,19 @@ class Form extends Component implements HasForms { - use InteractsWithForms, WithNotification; + use InteractsWithForms; + use WithNotification; public \Modules\Forms\Models\Form $formModel; public $data = []; + public ?int $team_id = null; // tells us which team the form submission is for in case this is a global form + public bool $formSubmitted = false; + public bool $needBootcamp = false; + public string $submitText; public function mount(\Modules\Forms\Models\Form $form, int $team_id = null, $submitText = 'Submit') diff --git a/src/Jobs/SendFormNotificationsJob.php b/src/Jobs/SendFormNotificationsJob.php index c27b7f4..908dcd6 100644 --- a/src/Jobs/SendFormNotificationsJob.php +++ b/src/Jobs/SendFormNotificationsJob.php @@ -15,7 +15,10 @@ class SendFormNotificationsJob implements ShouldQueue { - use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; + use Dispatchable; + use InteractsWithQueue; + use Queueable; + use SerializesModels; /** * Create a new job instance. diff --git a/src/Models/Form.php b/src/Models/Form.php index c87d11b..73e9aee 100644 --- a/src/Models/Form.php +++ b/src/Models/Form.php @@ -9,7 +9,8 @@ class Form extends Model { - use HasFactory, HasSlug; + use HasFactory; + use HasSlug; protected $casts = [ 'content' => 'array', diff --git a/src/Models/FormNotification.php b/src/Models/FormNotification.php index 00e58ab..17706b2 100644 --- a/src/Models/FormNotification.php +++ b/src/Models/FormNotification.php @@ -13,6 +13,7 @@ class FormNotification extends Model use HasFactory; protected $guarded = []; + protected $appends = ['send_date_edit']; // protected static function newFactory() diff --git a/src/Models/FormTemplate.php b/src/Models/FormTemplate.php index 6855ca8..c2ec88b 100644 --- a/src/Models/FormTemplate.php +++ b/src/Models/FormTemplate.php @@ -9,7 +9,8 @@ class FormTemplate extends Model { - use HasFactory, HasSlug; + use HasFactory; + use HasSlug; protected $fillable = [ 'name', diff --git a/src/Models/FormType.php b/src/Models/FormType.php index a8fcbd2..e87aebb 100644 --- a/src/Models/FormType.php +++ b/src/Models/FormType.php @@ -9,7 +9,8 @@ class FormType extends Model { - use HasFactory, HasSlug; + use HasFactory; + use HasSlug; protected $fillable = [ 'name', diff --git a/src/Providers/FormsServiceProvider.php b/src/Providers/FormsServiceProvider.php index ed296fb..c5f34ee 100644 --- a/src/Providers/FormsServiceProvider.php +++ b/src/Providers/FormsServiceProvider.php @@ -95,7 +95,8 @@ protected function registerConfig() module_path($this->moduleName, 'Config/config.php') => config_path($this->moduleNameLower . '.php'), ], 'config'); $this->mergeConfigFrom( - module_path($this->moduleName, 'Config/config.php'), $this->moduleNameLower + module_path($this->moduleName, 'Config/config.php'), + $this->moduleNameLower ); } diff --git a/src/Traits/Livewire/WithFormBuilder.php b/src/Traits/Livewire/WithFormBuilder.php index d45c455..dd04f18 100644 --- a/src/Traits/Livewire/WithFormBuilder.php +++ b/src/Traits/Livewire/WithFormBuilder.php @@ -15,20 +15,25 @@ use Illuminate\Support\Str; use Modules\Forms\Models\Form; use Modules\Forms\Models\FormType; -use OmniaDigital\OmniaLibrary\Livewire\WithNotification; use OmniaDigital\CatalystCore\Facades\Translate; +use OmniaDigital\OmniaLibrary\Livewire\WithNotification; /** * Add form builder to livewire component */ trait WithFormBuilder { - use InteractsWithForms, WithNotification; + use InteractsWithForms; + use WithNotification; public $name; + public $slug; + public $content; + public $team_id; + public $form_type_id; public function save($teamId = null): void @@ -134,8 +139,8 @@ protected function getFieldNameInput(): Grid ->lazy() ->afterStateUpdated(function (Closure $set, $state) { $name = Str::of($state) - ->snake() - ->lower() . uniqid('_'); + ->snake() + ->lower() . uniqid('_'); $set('name', $name); }) ->required(), diff --git a/src/Traits/Livewire/WithFormManagement.php b/src/Traits/Livewire/WithFormManagement.php index 43ba71e..7a23b36 100644 --- a/src/Traits/Livewire/WithFormManagement.php +++ b/src/Traits/Livewire/WithFormManagement.php @@ -11,13 +11,17 @@ trait WithFormManagement { public $confirmingFormRemoval = false; + public $formIdBeingRemoved = null; public $confirmingFormNotificationRemoval = false; + public $formNotificationIdBeingRemoved = null; public $confirmingPublishform = false; + public $formIdBeingPublished = null; + public $newStatus = ''; public function confirmPublishForm($formId, $status) diff --git a/tests/TestCase.php b/tests/TestCase.php index 1a1e800..6e9038d 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -16,9 +16,9 @@ use Filament\Widgets\WidgetsServiceProvider; use Illuminate\Database\Eloquent\Factories\Factory; use Livewire\LivewireServiceProvider; +use OmniaDigital\CatalystFormsPlugin\CatalystFormsPluginServiceProvider; use Orchestra\Testbench\TestCase as Orchestra; use RyanChandler\BladeCaptureDirective\BladeCaptureDirectiveServiceProvider; -use OmniaDigital\CatalystFormsPlugin\CatalystFormsPluginServiceProvider; class TestCase extends Orchestra { From 54fd7917e892f1062d732c58e3129a8b82f16169 Mon Sep 17 00:00:00 2001 From: Josh Torres Date: Wed, 1 Nov 2023 22:19:01 -0700 Subject: [PATCH 4/4] - move livewire directory - add dependencies for laravel and omnia library --- composer.json | 9 ++++++--- src/{Http => }/Livewire/Builder.php | 2 +- src/{Http => }/Livewire/Form.php | 2 +- src/{Http => }/Livewire/TeamApplicationForm.php | 4 ++-- src/{Http => }/Livewire/UserRegistrationForm.php | 4 ++-- src/Routes/web.php | 2 +- 6 files changed, 13 insertions(+), 10 deletions(-) rename src/{Http => }/Livewire/Builder.php (98%) rename src/{Http => }/Livewire/Form.php (98%) rename src/{Http => }/Livewire/TeamApplicationForm.php (91%) rename src/{Http => }/Livewire/UserRegistrationForm.php (95%) diff --git a/composer.json b/composer.json index 4dcc9d0..3bd95e8 100644 --- a/composer.json +++ b/composer.json @@ -22,8 +22,11 @@ "require": { "php": "^8.1", "filament/filament": "^3.0", - "spatie/laravel-package-tools": "^1.15.0", - "illuminate/contracts": "^10.0" + "illuminate/contracts": "^10.0", + "laravel/framework": "^10.30", + "laravel/jetstream": "^4.0", + "omnia-digital/library": "^2.0", + "spatie/laravel-package-tools": "^1.15.0" }, "require-dev": { "laravel/pint": "^1.0", @@ -75,4 +78,4 @@ }, "minimum-stability": "dev", "prefer-stable": true -} \ No newline at end of file +} diff --git a/src/Http/Livewire/Builder.php b/src/Livewire/Builder.php similarity index 98% rename from src/Http/Livewire/Builder.php rename to src/Livewire/Builder.php index 65b00ff..e7c6b17 100644 --- a/src/Http/Livewire/Builder.php +++ b/src/Livewire/Builder.php @@ -1,6 +1,6 @@ prefix('forms')->group(function () { Route::get('/forms/{form}', Form::class)->name('form');