Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,22 @@
</COPYRIGHT>
*/

namespace AidingApp\Engagement\Actions;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\HtmlString;

class GenerateEngagementBodyContent
{
public function __invoke(string|array $content, array $mergeData, Model $record, string $recordAttribute): HtmlString
return new class () extends Migration {
public function up(): void
{
$content = tiptap_converter()
->mergeTagsMap($mergeData)
->record($record, $recordAttribute)
->asHTML($content);
Schema::table('email_templates', function (Blueprint $table) {
$table->json('content')->nullable()->change();
});
}

return str($content)->sanitizeHtml()->toHtmlString();
public function down(): void
{
Schema::table('email_templates', function (Blueprint $table) {
$table->json('content')->nullable(false)->change();
});
}
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -34,59 +34,65 @@
</COPYRIGHT>
*/

namespace AidingApp\Engagement\Actions;
use Illuminate\Database\Migrations\Migration;
use Illuminate\Support\Facades\DB;

class GenerateTipTapBodyJson
{
public function __invoke(string $body, array $mergeTags = []): array
return new class () extends Migration {
public function up(): void
{
return json_decode(tiptap_converter()
->getEditor()
->setContent($body)
->descendants(function ($node) use ($mergeTags) {
if ($node->type !== 'paragraph') {
$this->processTable('email_templates', 'content');
$this->processTable('engagements', 'body');
$this->processTable('engagement_batches', 'body');
}

public function down(): void {}

protected function processTable(string $table, string $column): void
{
DB::table($table)
->whereNotNull($column)
->eachById(function (object $record) use ($table, $column) {
$body = json_decode($record->{$column}, associative: true);

if (! is_array($body)) {
return;
}

$content = collect();

foreach ($node->content as $item) {
preg_match_all('/{{2}[\s\S]*?}{2}|\s*\S+\s*/', $item->text, $tokens);
$changed = false;

if (blank($tokens)) {
continue;
}
$this->processNodes($body, $changed);

$content->push(
collect($tokens[0])
->map(
fn ($token) => in_array($token, $mergeTags)
? (object) $this->mergeTag($token)
: (object) $this->text($token, $item)
)
);
if (! $changed) {
return;
}
$node->content = $content->flatten()->toArray();
})
->getJSON(), true);
}

private function mergeTag(string $token): array
{
return [
'type' => 'mergeTag',
'attrs' => [
'id' => str($token)->remove(['{{', '}}'])->trim()->toString(),
],
];
DB::table($table)
->where('id', $record->id)
->update([$column => json_encode($body)]);
}, 100);
}

private function text(string $text, object $item): array
/**
* @param array<mixed> $node
*/
protected function processNodes(array &$node, bool &$changed): void
{
return [
'type' => 'text',
'text' => $text,
...collect($item)->except(['type', 'text'])->toArray(),
];
if (($node['type'] ?? null) === 'image') {
$width = $node['attrs']['width'] ?? null;

if (is_numeric($width) && $width > 500) {
$node['attrs']['width'] = null;
$node['attrs']['height'] = null;
$changed = true;
}
}

if (isset($node['content']) && is_array($node['content'])) {
foreach ($node['content'] as &$child) {
if (is_array($child)) {
$this->processNodes($child, $changed);
}
}
}
}
}
};
12 changes: 4 additions & 8 deletions app-modules/engagement/src/Actions/CreateEngagement.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public function execute(EngagementCreationData $data): Engagement
$engagement->recipient()->associate($data->recipient);
$engagement->channel = $data->channel;
$engagement->subject = $data->subject;
$engagement->body = $data->body;
$engagement->scheduled_at = $data->scheduledAt;

if (! $engagement->scheduled_at) {
Expand All @@ -59,14 +60,9 @@ public function execute(EngagementCreationData $data): Engagement
DB::transaction(function () use ($data, $engagement) {
$engagement->save();

[$engagement->body] = tiptap_converter()->saveImages(
$data->body,
disk: 's3-public',
record: $engagement,
recordAttribute: 'body',
newImages: $data->temporaryBodyImages,
);
$engagement->save();
if ($data->schema) {
$data->schema->model($engagement)->saveRelationships();
}

if (! $engagement->scheduled_at) {
$engagement->recipient->notify(new EngagementNotification($engagement)->afterCommit());
Expand Down
13 changes: 4 additions & 9 deletions app-modules/engagement/src/Actions/CreateEngagementBatch.php
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,14 @@ public function execute(EngagementCreationData $data): void
$engagementBatch->total_engagements = $data->recipient->count();
$engagementBatch->processed_engagements = 0;
$engagementBatch->successful_engagements = 0;
$engagementBatch->body = $data->body;

DB::transaction(function () use ($engagementBatch, $data) {
$engagementBatch->save();

[$engagementBatch->body] = tiptap_converter()->saveImages(
$data->body,
disk: 's3-public',
record: $engagementBatch,
recordAttribute: 'body',
newImages: $data->temporaryBodyImages,
);

$engagementBatch->save();
if ($data->schema) {
$data->schema->model($engagementBatch)->saveRelationships();
}
});

try {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
use AidingApp\Notification\Models\Contracts\CanBeNotified;
use App\Models\User;
use Carbon\CarbonInterface;
use Filament\Schemas\Schema;
use Illuminate\Database\Eloquent\Collection;
use Spatie\LaravelData\Data;

Expand All @@ -51,7 +52,7 @@ public function __construct(
public NotificationChannel $channel,
public ?string $subject = null,
public ?array $body = null,
public array $temporaryBodyImages = [],
public ?CarbonInterface $scheduledAt = null,
public ?Schema $schema = null,
) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,14 @@
use AidingApp\Engagement\Actions\CreateEngagementBatch;
use AidingApp\Engagement\DataTransferObjects\EngagementCreationData;
use AidingApp\Engagement\Models\EmailTemplate;
use AidingApp\Engagement\Models\EngagementBatch;
use AidingApp\Notification\Enums\NotificationChannel;
use Exception;
use Filament\Actions\Action;
use Filament\Actions\BulkAction;
use Filament\Forms\Components\Checkbox;
use Filament\Forms\Components\DateTimePicker;
use Filament\Forms\Components\RichEditor;
use Filament\Forms\Components\Select;
use Filament\Forms\Components\TextInput;
use Filament\Forms\Components\Toggle;
Expand All @@ -52,12 +55,12 @@
use Filament\Schemas\Components\Utilities\Set;
use Filament\Schemas\Components\Wizard\Step;
use Filament\Schemas\Schema;
use FilamentTiptapEditor\TiptapEditor;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Query\Expression;
use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;
use Livewire\Features\SupportFileUploads\TemporaryUploadedFile;
use Illuminate\Support\Str;
use Spatie\MediaLibrary\MediaCollections\Models\Media;

class BulkEngagementAction
{
Expand All @@ -67,6 +70,7 @@ public static function make(string $context): BulkAction
->icon('heroicon-o-chat-bubble-bottom-center-text')
->modalHeading('Send Bulk Engagement')
->modalDescription(fn (Collection $records) => "You have selected {$records->count()} {$context} to engage.")
->model(EngagementBatch::class)
->steps([
Step::make('Choose your delivery method')
->schema([
Expand All @@ -86,17 +90,13 @@ public static function make(string $context): BulkAction
->required()
->placeholder(__('Subject'))
->columnSpanFull(),
TiptapEditor::make('body')
->disk('s3-public')
RichEditor::make('body')
->label('Body')
->mergeTags($mergeTags = [
'contact full name',
'contact email',
])
->showMergeTagsInBlocksPanel(false)
->profile('email')
->toolbarButtons([['bold', 'italic', 'small', 'link'], ['h1', 'h2', 'h3', 'bulletList', 'orderedList', 'horizontalRule', 'attachFiles'], ['mergeTags']])
->activePanel('mergeTags')
->resizableImages()
->required()
->hintAction(fn (TiptapEditor $component) => Action::make('loadEmailTemplate')
->hintAction(fn (RichEditor $component) => Action::make('loadEmailTemplate')
->schema([
Select::make('emailTemplate')
->searchable()
Expand All @@ -111,10 +111,9 @@ public static function make(string $context): BulkAction
->pluck('name', 'id')
->toArray();
})
->getOptionLabelUsing(fn (string $value): ?string => EmailTemplate::query()
->whereKey($value)
->value('name'))
->getSearchResultsUsing(function (Get $get, string $search): array {
$search = Str::lower($search);

return EmailTemplate::query()
->when(
$get('onlyMyTemplates'),
Expand All @@ -129,7 +128,8 @@ public static function make(string $context): BulkAction
->limit(50)
->pluck('name', 'id')
->toArray();
}),
})
->getOptionLabelUsing(fn (string $value): ?string => EmailTemplate::find($value)?->name),
Checkbox::make('onlyMyTemplates')
->label('Only show my templates')
->live()
Expand All @@ -142,19 +142,36 @@ public static function make(string $context): BulkAction
->action(function (array $data) use ($component) {
$template = EmailTemplate::find($data['emailTemplate']);

if (! $template) {
return;
if (! $template instanceof EmailTemplate) {
throw new Exception('template is not instance of EmailTemplate');
}

$component->state(
$component->generateImageUrls($template->content),
);
$component->state($template->content);
}))
->helperText('You can insert student information by typing {{ and choosing a merge value to insert.')
->columnSpanFull(),
->getFileAttachmentUrlFromAnotherRecordUsing(function (mixed $file): ?string {
return Media::query()
->where('uuid', $file)
->where('model_type', (new EmailTemplate())->getMorphClass())
->first()
?->getUrl();
})
->saveFileAttachmentFromAnotherRecordUsing(function (mixed $file, EngagementBatch $record): ?string {
return Media::query()
->where('uuid', $file)
->where('model_type', (new EmailTemplate())->getMorphClass())
->first()
?->copy($record, 'body', 's3-public')
->uuid;
})
->helperText('You can insert recipient or your information by typing {{ and choosing a merge value to insert.')
->columnSpanFull()
->json(),
Actions::make([
BulkDraftWithAiAction::make()
->mergeTags($mergeTags),
->mergeTags([
'contact full name',
'contact email',
]),
]),
]),
Step::make('Schedule')
Expand All @@ -171,20 +188,16 @@ public static function make(string $context): BulkAction
->action(function (Collection $records, array $data, Schema $schema) {
$channel = NotificationChannel::parse($data['channel']);

$data['body'] ??= ['type' => 'doc', 'content' => []];

app(CreateEngagementBatch::class)->execute(new EngagementCreationData(
user: auth()->user(),
recipient: $records,
channel: $channel,
subject: $data['subject'] ?? null,
body: $data['body'] ?? null,
temporaryBodyImages: array_map(
fn (TemporaryUploadedFile $file): array => [
'extension' => $file->getClientOriginalExtension(),
'path' => (fn () => $this->path)->call($file),
],
$schema->getFlatFields()['body']->getTemporaryImages(),
),
body: $data['body'],
scheduledAt: ($data['send_later'] ?? false) ? Carbon::parse($data['scheduled_at'] ?? null) : null,
schema: $schema,
));
})
->modalSubmitActionLabel('Send')
Expand Down
Loading