mirror of
https://github.com/pixelfed/pixelfed.git
synced 2024-11-09 16:24:51 +00:00
Add Curated Onboarding Templates
This commit is contained in:
parent
795e91e3bc
commit
071163b47b
9 changed files with 590 additions and 51 deletions
|
@ -2,42 +2,43 @@
|
||||||
|
|
||||||
namespace App\Http\Controllers;
|
namespace App\Http\Controllers;
|
||||||
|
|
||||||
use Illuminate\Http\Request;
|
|
||||||
use App\Models\CuratedRegister;
|
|
||||||
use App\Models\CuratedRegisterActivity;
|
|
||||||
use Illuminate\Support\Str;
|
|
||||||
use Illuminate\Support\Facades\Mail;
|
|
||||||
use App\Mail\CuratedRegisterRequestDetailsFromUser;
|
|
||||||
use App\Mail\CuratedRegisterAcceptUser;
|
use App\Mail\CuratedRegisterAcceptUser;
|
||||||
use App\Mail\CuratedRegisterRejectUser;
|
use App\Mail\CuratedRegisterRejectUser;
|
||||||
|
use App\Mail\CuratedRegisterRequestDetailsFromUser;
|
||||||
|
use App\Models\CuratedRegister;
|
||||||
|
use App\Models\CuratedRegisterActivity;
|
||||||
|
use App\Models\CuratedRegisterTemplate;
|
||||||
use App\User;
|
use App\User;
|
||||||
|
use Illuminate\Http\Request;
|
||||||
|
use Illuminate\Support\Facades\Mail;
|
||||||
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
class AdminCuratedRegisterController extends Controller
|
class AdminCuratedRegisterController extends Controller
|
||||||
{
|
{
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->middleware(['auth','admin']);
|
$this->middleware(['auth', 'admin']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function index(Request $request)
|
public function index(Request $request)
|
||||||
{
|
{
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'filter' => 'sometimes|in:open,all,awaiting,approved,rejected,responses',
|
'filter' => 'sometimes|in:open,all,awaiting,approved,rejected,responses',
|
||||||
'sort' => 'sometimes|in:asc,desc'
|
'sort' => 'sometimes|in:asc,desc',
|
||||||
]);
|
]);
|
||||||
$filter = $request->input('filter', 'open');
|
$filter = $request->input('filter', 'open');
|
||||||
$sort = $request->input('sort', 'asc');
|
$sort = $request->input('sort', 'asc');
|
||||||
$records = CuratedRegister::when($filter, function($q, $filter) {
|
$records = CuratedRegister::when($filter, function ($q, $filter) {
|
||||||
if($filter === 'open') {
|
if ($filter === 'open') {
|
||||||
return $q->where('is_rejected', false)
|
return $q->where('is_rejected', false)
|
||||||
->where(function($query) {
|
->where(function ($query) {
|
||||||
return $query->where('user_has_responded', true)->orWhere('is_awaiting_more_info', false);
|
return $query->where('user_has_responded', true)->orWhere('is_awaiting_more_info', false);
|
||||||
})
|
})
|
||||||
->whereNotNull('email_verified_at')
|
->whereNotNull('email_verified_at')
|
||||||
->whereIsClosed(false);
|
->whereIsClosed(false);
|
||||||
} else if($filter === 'all') {
|
} elseif ($filter === 'all') {
|
||||||
return $q;
|
return $q;
|
||||||
} else if($filter === 'responses') {
|
} elseif ($filter === 'responses') {
|
||||||
return $q->whereIsClosed(false)
|
return $q->whereIsClosed(false)
|
||||||
->whereNotNull('email_verified_at')
|
->whereNotNull('email_verified_at')
|
||||||
->where('user_has_responded', true)
|
->where('user_has_responded', true)
|
||||||
|
@ -54,17 +55,19 @@ class AdminCuratedRegisterController extends Controller
|
||||||
return $q->whereIsClosed(true)->whereIsRejected(true);
|
return $q->whereIsClosed(true)->whereIsRejected(true);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
->when($sort, function($query, $sort) {
|
->when($sort, function ($query, $sort) {
|
||||||
return $query->orderBy('id', $sort);
|
return $query->orderBy('id', $sort);
|
||||||
})
|
})
|
||||||
->paginate(10)
|
->paginate(10)
|
||||||
->withQueryString();
|
->withQueryString();
|
||||||
|
|
||||||
return view('admin.curated-register.index', compact('records', 'filter'));
|
return view('admin.curated-register.index', compact('records', 'filter'));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function show(Request $request, $id)
|
public function show(Request $request, $id)
|
||||||
{
|
{
|
||||||
$record = CuratedRegister::findOrFail($id);
|
$record = CuratedRegister::findOrFail($id);
|
||||||
|
|
||||||
return view('admin.curated-register.show', compact('record'));
|
return view('admin.curated-register.show', compact('record'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,10 +83,10 @@ class AdminCuratedRegisterController extends Controller
|
||||||
'message' => null,
|
'message' => null,
|
||||||
'link' => null,
|
'link' => null,
|
||||||
'timestamp' => $record->created_at,
|
'timestamp' => $record->created_at,
|
||||||
]
|
],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
if($record->email_verified_at) {
|
if ($record->email_verified_at) {
|
||||||
$res->push([
|
$res->push([
|
||||||
'id' => 3,
|
'id' => 3,
|
||||||
'action' => 'email_verified_at',
|
'action' => 'email_verified_at',
|
||||||
|
@ -99,10 +102,11 @@ class AdminCuratedRegisterController extends Controller
|
||||||
$idx = 4;
|
$idx = 4;
|
||||||
$userResponses = collect([]);
|
$userResponses = collect([]);
|
||||||
|
|
||||||
foreach($activities as $activity) {
|
foreach ($activities as $activity) {
|
||||||
$idx++;
|
$idx++;
|
||||||
if($activity->from_user) {
|
if ($activity->from_user) {
|
||||||
$userResponses->push($activity);
|
$userResponses->push($activity);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$res->push([
|
$res->push([
|
||||||
|
@ -116,20 +120,22 @@ class AdminCuratedRegisterController extends Controller
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($userResponses as $ur) {
|
foreach ($userResponses as $ur) {
|
||||||
$res = $res->map(function($r) use($ur) {
|
$res = $res->map(function ($r) use ($ur) {
|
||||||
if(!isset($r['aid'])) {
|
if (! isset($r['aid'])) {
|
||||||
return $r;
|
return $r;
|
||||||
}
|
}
|
||||||
if($ur->reply_to_id === $r['aid']) {
|
if ($ur->reply_to_id === $r['aid']) {
|
||||||
$r['user_response'] = $ur;
|
$r['user_response'] = $ur;
|
||||||
|
|
||||||
return $r;
|
return $r;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $r;
|
return $r;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if($record->is_approved) {
|
if ($record->is_approved) {
|
||||||
$idx++;
|
$idx++;
|
||||||
$res->push([
|
$res->push([
|
||||||
'id' => $idx,
|
'id' => $idx,
|
||||||
|
@ -139,7 +145,7 @@ class AdminCuratedRegisterController extends Controller
|
||||||
'link' => null,
|
'link' => null,
|
||||||
'timestamp' => $record->action_taken_at,
|
'timestamp' => $record->action_taken_at,
|
||||||
]);
|
]);
|
||||||
} else if ($record->is_rejected) {
|
} elseif ($record->is_rejected) {
|
||||||
$idx++;
|
$idx++;
|
||||||
$res->push([
|
$res->push([
|
||||||
'id' => $idx,
|
'id' => $idx,
|
||||||
|
@ -157,13 +163,14 @@ class AdminCuratedRegisterController extends Controller
|
||||||
public function apiMessagePreviewStore(Request $request, $id)
|
public function apiMessagePreviewStore(Request $request, $id)
|
||||||
{
|
{
|
||||||
$record = CuratedRegister::findOrFail($id);
|
$record = CuratedRegister::findOrFail($id);
|
||||||
|
|
||||||
return $request->all();
|
return $request->all();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function apiMessageSendStore(Request $request, $id)
|
public function apiMessageSendStore(Request $request, $id)
|
||||||
{
|
{
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'message' => 'required|string|min:5|max:1000'
|
'message' => 'required|string|min:5|max:1000',
|
||||||
]);
|
]);
|
||||||
$record = CuratedRegister::findOrFail($id);
|
$record = CuratedRegister::findOrFail($id);
|
||||||
abort_if($record->email_verified_at === null, 400, 'Cannot message an unverified email');
|
abort_if($record->email_verified_at === null, 400, 'Cannot message an unverified email');
|
||||||
|
@ -179,6 +186,7 @@ class AdminCuratedRegisterController extends Controller
|
||||||
$record->user_has_responded = false;
|
$record->user_has_responded = false;
|
||||||
$record->save();
|
$record->save();
|
||||||
Mail::to($record->email)->send(new CuratedRegisterRequestDetailsFromUser($record, $activity));
|
Mail::to($record->email)->send(new CuratedRegisterRequestDetailsFromUser($record, $activity));
|
||||||
|
|
||||||
return $request->all();
|
return $request->all();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,22 +196,23 @@ class AdminCuratedRegisterController extends Controller
|
||||||
abort_if($record->email_verified_at === null, 400, 'Cannot message an unverified email');
|
abort_if($record->email_verified_at === null, 400, 'Cannot message an unverified email');
|
||||||
$activity = new CuratedRegisterActivity;
|
$activity = new CuratedRegisterActivity;
|
||||||
$activity->message = $request->input('message');
|
$activity->message = $request->input('message');
|
||||||
|
|
||||||
return new \App\Mail\CuratedRegisterRequestDetailsFromUser($record, $activity);
|
return new \App\Mail\CuratedRegisterRequestDetailsFromUser($record, $activity);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public function previewMessageShow(Request $request, $id)
|
public function previewMessageShow(Request $request, $id)
|
||||||
{
|
{
|
||||||
$record = CuratedRegister::findOrFail($id);
|
$record = CuratedRegister::findOrFail($id);
|
||||||
abort_if($record->email_verified_at === null, 400, 'Cannot message an unverified email');
|
abort_if($record->email_verified_at === null, 400, 'Cannot message an unverified email');
|
||||||
$record->message = $request->input('message');
|
$record->message = $request->input('message');
|
||||||
|
|
||||||
return new \App\Mail\CuratedRegisterSendMessage($record);
|
return new \App\Mail\CuratedRegisterSendMessage($record);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function apiHandleReject(Request $request, $id)
|
public function apiHandleReject(Request $request, $id)
|
||||||
{
|
{
|
||||||
$this->validate($request, [
|
$this->validate($request, [
|
||||||
'action' => 'required|in:reject-email,reject-silent'
|
'action' => 'required|in:reject-email,reject-silent',
|
||||||
]);
|
]);
|
||||||
$action = $request->input('action');
|
$action = $request->input('action');
|
||||||
$record = CuratedRegister::findOrFail($id);
|
$record = CuratedRegister::findOrFail($id);
|
||||||
|
@ -212,9 +221,10 @@ class AdminCuratedRegisterController extends Controller
|
||||||
$record->is_closed = true;
|
$record->is_closed = true;
|
||||||
$record->action_taken_at = now();
|
$record->action_taken_at = now();
|
||||||
$record->save();
|
$record->save();
|
||||||
if($action === 'reject-email') {
|
if ($action === 'reject-email') {
|
||||||
Mail::to($record->email)->send(new CuratedRegisterRejectUser($record));
|
Mail::to($record->email)->send(new CuratedRegisterRejectUser($record));
|
||||||
}
|
}
|
||||||
|
|
||||||
return [200];
|
return [200];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,10 +243,89 @@ class AdminCuratedRegisterController extends Controller
|
||||||
'password' => $record->password,
|
'password' => $record->password,
|
||||||
'app_register_ip' => $record->ip_address,
|
'app_register_ip' => $record->ip_address,
|
||||||
'email_verified_at' => now(),
|
'email_verified_at' => now(),
|
||||||
'register_source' => 'cur_onboarding'
|
'register_source' => 'cur_onboarding',
|
||||||
]);
|
]);
|
||||||
|
|
||||||
Mail::to($record->email)->send(new CuratedRegisterAcceptUser($record));
|
Mail::to($record->email)->send(new CuratedRegisterAcceptUser($record));
|
||||||
|
|
||||||
return [200];
|
return [200];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function templates(Request $request)
|
||||||
|
{
|
||||||
|
$templates = CuratedRegisterTemplate::paginate(10);
|
||||||
|
|
||||||
|
return view('admin.curated-register.templates', compact('templates'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function templateCreate(Request $request)
|
||||||
|
{
|
||||||
|
return view('admin.curated-register.template-create');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function templateEdit(Request $request, $id)
|
||||||
|
{
|
||||||
|
$template = CuratedRegisterTemplate::findOrFail($id);
|
||||||
|
|
||||||
|
return view('admin.curated-register.template-edit', compact('template'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function templateEditStore(Request $request, $id)
|
||||||
|
{
|
||||||
|
$this->validate($request, [
|
||||||
|
'name' => 'required|string|max:30',
|
||||||
|
'content' => 'required|string|min:5|max:3000',
|
||||||
|
'description' => 'nullable|sometimes|string|max:1000',
|
||||||
|
'active' => 'sometimes',
|
||||||
|
]);
|
||||||
|
$template = CuratedRegisterTemplate::findOrFail($id);
|
||||||
|
$template->name = $request->input('name');
|
||||||
|
$template->content = $request->input('content');
|
||||||
|
$template->description = $request->input('description');
|
||||||
|
$template->is_active = $request->boolean('active');
|
||||||
|
$template->save();
|
||||||
|
|
||||||
|
return redirect()->back()->with('status', 'Successfully updated template!');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function templateDelete(Request $request, $id)
|
||||||
|
{
|
||||||
|
$template = CuratedRegisterTemplate::findOrFail($id);
|
||||||
|
$template->delete();
|
||||||
|
|
||||||
|
return redirect(route('admin.curated-onboarding.templates'))->with('status', 'Successfully deleted template!');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function templateStore(Request $request)
|
||||||
|
{
|
||||||
|
$this->validate($request, [
|
||||||
|
'name' => 'required|string|max:30',
|
||||||
|
'content' => 'required|string|min:5|max:3000',
|
||||||
|
'description' => 'nullable|sometimes|string|max:1000',
|
||||||
|
'active' => 'sometimes',
|
||||||
|
]);
|
||||||
|
CuratedRegisterTemplate::create([
|
||||||
|
'name' => $request->input('name'),
|
||||||
|
'content' => $request->input('content'),
|
||||||
|
'description' => $request->input('description'),
|
||||||
|
'is_active' => $request->boolean('active'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return redirect(route('admin.curated-onboarding.templates'))->with('status', 'Successfully created new template!');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getActiveTemplates(Request $request)
|
||||||
|
{
|
||||||
|
$templates = CuratedRegisterTemplate::whereIsActive(true)
|
||||||
|
->orderBy('order')
|
||||||
|
->get()
|
||||||
|
->map(function ($tmp) {
|
||||||
|
return [
|
||||||
|
'name' => $tmp->name,
|
||||||
|
'content' => $tmp->content,
|
||||||
|
];
|
||||||
|
});
|
||||||
|
|
||||||
|
return response()->json($templates);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
19
app/Models/CuratedRegisterTemplate.php
Normal file
19
app/Models/CuratedRegisterTemplate.php
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace App\Models;
|
||||||
|
|
||||||
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
|
||||||
|
class CuratedRegisterTemplate extends Model
|
||||||
|
{
|
||||||
|
use HasFactory;
|
||||||
|
|
||||||
|
protected $fillable = [
|
||||||
|
'name', 'description', 'content', 'is_active', 'order',
|
||||||
|
];
|
||||||
|
|
||||||
|
protected $casts = [
|
||||||
|
'is_active' => 'boolean',
|
||||||
|
];
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::create('curated_register_templates', function (Blueprint $table) {
|
||||||
|
$table->id();
|
||||||
|
$table->string('name')->nullable();
|
||||||
|
$table->text('description')->nullable();
|
||||||
|
$table->text('content')->nullable();
|
||||||
|
$table->boolean('is_active')->default(false)->index();
|
||||||
|
$table->tinyInteger('order')->default(10)->unsigned()->index();
|
||||||
|
$table->timestamps();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::dropIfExists('curated_register_templates');
|
||||||
|
}
|
||||||
|
};
|
|
@ -46,6 +46,21 @@
|
||||||
<p class="lead font-weight-bold text-center">Request Additional Details</p>
|
<p class="lead font-weight-bold text-center">Request Additional Details</p>
|
||||||
<p class="text-muted">Use this form to request additional details. Once you press Send, we'll send the potential user an email with a special link they can visit with a form that they can provide additional details with. You can also Preview the email before it's sent.</p>
|
<p class="text-muted">Use this form to request additional details. Once you press Send, we'll send the potential user an email with a special link they can visit with a form that they can provide additional details with. You can also Preview the email before it's sent.</p>
|
||||||
|
|
||||||
|
<div v-if="responseTemplates && responseTemplates.length" class="my-3">
|
||||||
|
<p class="small font-weight-bold mb-1">Template Responses</p>
|
||||||
|
|
||||||
|
<div class="d-grid">
|
||||||
|
<template v-for="tmpl in responseTemplates">
|
||||||
|
<button
|
||||||
|
class="btn btn-lighter btn-sm py-1 font-weight-bold rounded-lg text-dark border border-muted px-3"
|
||||||
|
style="font-size: 13px;"
|
||||||
|
@click="useTemplate(tmpl)">
|
||||||
|
<i class="far fa-plus mr-1 text-muted"></i> @{{ tmpl.name.slice(0, 25) }}
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="request-form">
|
<div class="request-form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="requestDetailsMessageInput" class="small text-muted">Your Message:</label>
|
<label for="requestDetailsMessageInput" class="small text-muted">Your Message:</label>
|
||||||
|
@ -60,7 +75,7 @@
|
||||||
<p class="help-text small text-right">
|
<p class="help-text small text-right">
|
||||||
<span>@{{ composeMessage && composeMessage.length ? composeMessage.length : 0 }}</span>
|
<span>@{{ composeMessage && composeMessage.length ? composeMessage.length : 0 }}</span>
|
||||||
<span>/</span>
|
<span>/</span>
|
||||||
<span>500</span>
|
<span>2000</span>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex">
|
<div class="d-flex">
|
||||||
|
@ -76,6 +91,12 @@
|
||||||
target="_blank">
|
target="_blank">
|
||||||
Preview
|
Preview
|
||||||
</a>
|
</a>
|
||||||
|
<a
|
||||||
|
v-if="composeMessage && composeMessage.length"
|
||||||
|
class="btn btn-outline-danger text-danger rounded-pill btn-sm px-4"
|
||||||
|
@click="composeMessage = null">
|
||||||
|
Clear
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -90,6 +111,21 @@
|
||||||
<p class="lead font-weight-bold text-center">Send Message</p>
|
<p class="lead font-weight-bold text-center">Send Message</p>
|
||||||
<p class="text-muted">Use this form to send a message to the applicant. Once you press Send, we'll send the potential user an email with your message. You can also Preview the email before it's sent.</p>
|
<p class="text-muted">Use this form to send a message to the applicant. Once you press Send, we'll send the potential user an email with your message. You can also Preview the email before it's sent.</p>
|
||||||
|
|
||||||
|
<div v-if="responseTemplates && responseTemplates.length" class="my-3">
|
||||||
|
<p class="small font-weight-bold mb-1">Template Responses</p>
|
||||||
|
|
||||||
|
<div class="d-grid">
|
||||||
|
<template v-for="tmpl in responseTemplates">
|
||||||
|
<button
|
||||||
|
class="btn btn-lighter btn-sm py-1 font-weight-bold rounded-lg text-dark border border-muted px-3"
|
||||||
|
style="font-size: 13px;"
|
||||||
|
@click="useTemplateMessage(tmpl)">
|
||||||
|
<i class="far fa-plus mr-1 text-muted"></i> @{{ tmpl.name.slice(0, 25) }}
|
||||||
|
</button>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="request-form">
|
<div class="request-form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="sendMessageInput" class="small text-muted">Your Message:</label>
|
<label for="sendMessageInput" class="small text-muted">Your Message:</label>
|
||||||
|
@ -187,11 +223,13 @@
|
||||||
messageFormOpen: false,
|
messageFormOpen: false,
|
||||||
composeMessage: null,
|
composeMessage: null,
|
||||||
messageBody: null,
|
messageBody: null,
|
||||||
|
responseTemplates: [],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
mounted() {
|
mounted() {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
this.fetchResponseTemplates();
|
||||||
this.fetchActivities();
|
this.fetchActivities();
|
||||||
}, 1000)
|
}, 1000)
|
||||||
},
|
},
|
||||||
|
@ -233,10 +271,16 @@
|
||||||
return str;
|
return str;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
fetchResponseTemplates() {
|
||||||
|
axios.get('/i/admin/api/curated-onboarding/templates/get')
|
||||||
|
.then(res => {
|
||||||
|
this.responseTemplates = res.data;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
fetchActivities() {
|
fetchActivities() {
|
||||||
axios.get('/i/admin/api/curated-onboarding/show/{{$id}}/activity-log')
|
axios.get('/i/admin/api/curated-onboarding/show/{{$id}}/activity-log')
|
||||||
.then(res => {
|
.then(res => {
|
||||||
console.log(res.data);
|
|
||||||
this.activities = res.data;
|
this.activities = res.data;
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
|
@ -379,7 +423,15 @@
|
||||||
|
|
||||||
openUserResponse(activity) {
|
openUserResponse(activity) {
|
||||||
swal('User Response', activity.user_response.message)
|
swal('User Response', activity.user_response.message)
|
||||||
}
|
},
|
||||||
|
|
||||||
|
useTemplate(tmpl) {
|
||||||
|
this.composeMessage = tmpl.content;
|
||||||
|
},
|
||||||
|
|
||||||
|
useTemplateMessage(tmpl) {
|
||||||
|
this.messageBody = tmpl.content;
|
||||||
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<ul class="nav nav-pills">
|
<ul class="nav nav-pills">
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link {{request()->has('filter') ? '':'active'}}" href="/i/admin/curated-onboarding/home">Open Applications</a>
|
<a class="nav-link {{!request()->is('*home') || request()->has('filter') ? '':'active'}}" href="/i/admin/curated-onboarding/home">Open Applications</a>
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link {{request()->has('filter') && request()->filter == 'responses' ? 'active':''}}" href="/i/admin/curated-onboarding/home?filter=responses">User Response Replies</a>
|
<a class="nav-link {{request()->has('filter') && request()->filter == 'responses' ? 'active':''}}" href="/i/admin/curated-onboarding/home?filter=responses">User Response Replies</a>
|
||||||
|
@ -32,6 +32,9 @@
|
||||||
<li class="nav-item">
|
<li class="nav-item">
|
||||||
<a class="nav-link {{request()->has('filter') && request()->filter == 'all' ? 'active':''}}" href="/i/admin/curated-onboarding/home?filter=all&sort=desc">All Applications</a>
|
<a class="nav-link {{request()->has('filter') && request()->filter == 'all' ? 'active':''}}" href="/i/admin/curated-onboarding/home?filter=all&sort=desc">All Applications</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link {{ request()->is('*templates*') ? 'active' : ''}}" href="/i/admin/curated-onboarding/templates">Templates</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
@extends('admin.partial.template-full')
|
||||||
|
|
||||||
|
@section('section')
|
||||||
|
</div><div class="header bg-primary pb-3 mt-n4">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="header-body">
|
||||||
|
<div class="row align-items-center py-4">
|
||||||
|
<div class="col-lg-8 col-12">
|
||||||
|
<p class="display-1 text-white d-inline-block mb-0">Curated Onboarding</p>
|
||||||
|
<p class="text-white mb-0">The ideal solution for communities seeking a balance between open registration and invite-only membership</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if((bool) config_cache('instance.curated_registration.enabled'))
|
||||||
|
<div class="m-n2 m-lg-4">
|
||||||
|
<div class="container-fluid mt-4">
|
||||||
|
@include('admin.curated-register.partials.nav')
|
||||||
|
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-12 col-lg-6">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="display-4">Create Template</h2>
|
||||||
|
<p class="lead my-0">Create re-usable templates of messages and application requests.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-12 col-lg-6">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
@if ($errors->any())
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
@foreach ($errors->all() as $error)
|
||||||
|
<p class="font-weight-bold mb-0">{{ $error }}</p>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
<form method="post">
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="small font-weight-bold">Shortcut/Name</label>
|
||||||
|
<input
|
||||||
|
class="form-control"
|
||||||
|
name="name"
|
||||||
|
value="{{old('name')}}"
|
||||||
|
placeholder="An optional name/shortcut for easy access" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="small font-weight-bold">Content</label>
|
||||||
|
<textarea
|
||||||
|
class="form-control"
|
||||||
|
name="content"
|
||||||
|
value="{{old('content')}}"
|
||||||
|
rows="8"
|
||||||
|
placeholder="Add your custom message template here..."></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p class="font-weight-bold">
|
||||||
|
<a class="font-weight-bold small" data-toggle="collapse" href="#collapseDescription" aria-expanded="false" aria-controls="collapseDescription">
|
||||||
|
Add optional description
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<div class="collapse" id="collapseDescription">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="small font-weight-bold">Description</label>
|
||||||
|
<textarea
|
||||||
|
class="form-control"
|
||||||
|
name="description"
|
||||||
|
rows="4"
|
||||||
|
placeholder="Add an optional description that is only visible to admins..."></textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="custom-control custom-checkbox">
|
||||||
|
<input type="checkbox" class="custom-control-input" id="active" name="active" checked>
|
||||||
|
<label class="custom-control-label font-weight-bold" for="active">Mark as Active</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<button class="btn btn-primary btn-block rounded-pill font-weight-bold">Create Template</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@endsection
|
148
resources/views/admin/curated-register/template-edit.blade.php
Normal file
148
resources/views/admin/curated-register/template-edit.blade.php
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
@extends('admin.partial.template-full')
|
||||||
|
|
||||||
|
@section('section')
|
||||||
|
</div><div class="header bg-primary pb-3 mt-n4">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="header-body">
|
||||||
|
<div class="row align-items-center py-4">
|
||||||
|
<div class="col-lg-8 col-12">
|
||||||
|
<p class="display-1 text-white d-inline-block mb-0">Curated Onboarding</p>
|
||||||
|
<p class="text-white mb-0">The ideal solution for communities seeking a balance between open registration and invite-only membership</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if((bool) config_cache('instance.curated_registration.enabled'))
|
||||||
|
<div class="m-n2 m-lg-4">
|
||||||
|
<div class="container-fluid mt-4">
|
||||||
|
@include('admin.curated-register.partials.nav')
|
||||||
|
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-12 col-lg-8">
|
||||||
|
@if (session('status'))
|
||||||
|
<div class="alert alert-success font-weight-bold lead" id="shm">
|
||||||
|
{{ session('status') }}
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
setTimeout(() => document.getElementById('shm').classList.add('animate__animated', 'animate__bounceOutLeft'), 2000);
|
||||||
|
setTimeout(() => document.getElementById('shm').style.display = 'none', 2500);
|
||||||
|
</script>
|
||||||
|
@endif
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h2 class="display-4 mb-0">Edit Template</h2>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row justify-content-center">
|
||||||
|
<div class="col-12 col-lg-8">
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
@if ($errors->any())
|
||||||
|
<div class="alert alert-danger">
|
||||||
|
@foreach ($errors->all() as $error)
|
||||||
|
<p class="font-weight-bold mb-0">{{ $error }}</p>
|
||||||
|
@endforeach
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
<form method="post" id="updateForm">
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="small font-weight-bold">Shortcut/Name</label>
|
||||||
|
<input
|
||||||
|
class="form-control"
|
||||||
|
name="name"
|
||||||
|
value="{{$template->name}}"
|
||||||
|
placeholder="An optional name/shortcut for easy access" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="small font-weight-bold">Content</label>
|
||||||
|
<textarea
|
||||||
|
class="form-control"
|
||||||
|
name="content"
|
||||||
|
rows="{{$template->content && strlen($template->content) > 500 ? 16 : 5}}"
|
||||||
|
placeholder="Add your custom message template here...">{{$template->content}}</textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if($template->description == null)
|
||||||
|
<p class="font-weight-bold">
|
||||||
|
<a class="font-weight-bold small" data-toggle="collapse" href="#collapseDescription" aria-expanded="false" aria-controls="collapseDescription">
|
||||||
|
Add optional description
|
||||||
|
</a>
|
||||||
|
</p>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
<div class="collapse {{ $template->description === null ? '':'show'}}" id="collapseDescription">
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="small font-weight-bold">Description</label>
|
||||||
|
<textarea
|
||||||
|
class="form-control"
|
||||||
|
name="description"
|
||||||
|
rows="4"
|
||||||
|
placeholder="Add an optional description that is only visible to admins...">{{ $template->description }}</textarea>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="custom-control custom-checkbox">
|
||||||
|
<input type="checkbox" class="custom-control-input" id="active" name="active" {{ $template->is_active ? 'checked' : ''}}>
|
||||||
|
<label class="custom-control-label font-weight-bold" for="active">Mark as Active</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
<div class="d-flex">
|
||||||
|
<button type="button" class="btn btn-primary flex-grow-1 rounded-pill font-weight-bold" id="saveBtn">Save</button>
|
||||||
|
<button type="button" class="btn btn-danger rounded-pill font-weight-bold" id="deleteBtn">Delete</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<form method="post" id="deleteForm">
|
||||||
|
@method('DELETE')
|
||||||
|
@csrf
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@endsection
|
||||||
|
|
||||||
|
@push('scripts')
|
||||||
|
<script>
|
||||||
|
$('#saveBtn').click(() => {
|
||||||
|
$('#updateForm').submit()
|
||||||
|
})
|
||||||
|
$('#deleteBtn').click(() => {
|
||||||
|
swal({
|
||||||
|
title: 'Confirm Deletion',
|
||||||
|
text: 'Are you sure you want to delete this template? It will not be recoverable',
|
||||||
|
icon: 'warning',
|
||||||
|
dangerMode: true,
|
||||||
|
buttons: {
|
||||||
|
close: {
|
||||||
|
text: "Close",
|
||||||
|
value: "close",
|
||||||
|
close: true,
|
||||||
|
className: "swal-button--cancel"
|
||||||
|
},
|
||||||
|
confirm: {
|
||||||
|
text: "Delete",
|
||||||
|
value: "delete",
|
||||||
|
className: "btn-danger"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).then(res => {
|
||||||
|
if(res == 'delete') {
|
||||||
|
$('#deleteForm').submit();
|
||||||
|
// window.location.href = '/i/admin/curated-onboarding/templates';
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
@endpush
|
91
resources/views/admin/curated-register/templates.blade.php
Normal file
91
resources/views/admin/curated-register/templates.blade.php
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
@extends('admin.partial.template-full')
|
||||||
|
|
||||||
|
@section('section')
|
||||||
|
</div><div class="header bg-primary pb-3 mt-n4">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="header-body">
|
||||||
|
<div class="row align-items-center py-4">
|
||||||
|
<div class="col-lg-8 col-12">
|
||||||
|
<p class="display-1 text-white d-inline-block mb-0">Curated Onboarding</p>
|
||||||
|
<p class="text-white mb-0">The ideal solution for communities seeking a balance between open registration and invite-only membership</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@if((bool) config_cache('instance.curated_registration.enabled'))
|
||||||
|
<div class="m-n2 m-lg-4">
|
||||||
|
<div class="container-fluid mt-4">
|
||||||
|
@include('admin.curated-register.partials.nav')
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
@if (session('status'))
|
||||||
|
<div class="alert alert-success font-weight-bold lead" id="shm">
|
||||||
|
{{ session('status') }}
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
setTimeout(() => document.getElementById('shm').classList.add('animate__animated', 'animate__bounceOutLeft'), 2000);
|
||||||
|
setTimeout(() => document.getElementById('shm').style.display = 'none', 2500);
|
||||||
|
</script>
|
||||||
|
@endif
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body d-flex justify-content-between align-items-center">
|
||||||
|
<p class="lead my-0">Create and manage re-usable templates of messages and application requests.</p>
|
||||||
|
<a class="btn btn-primary font-weight-bold rounded-pill" href="{{route('admin.curated-onboarding.create-template')}}">Create new Template</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12">
|
||||||
|
|
||||||
|
<div class="table-responsive rounded">
|
||||||
|
<table class="table table-dark">
|
||||||
|
<thead class="thead-dark">
|
||||||
|
<tr>
|
||||||
|
<th scope="col">ID</th>
|
||||||
|
<th scope="col">Shortcut/Name</th>
|
||||||
|
<th scope="col">Content</th>
|
||||||
|
<th scope="col">Active</th>
|
||||||
|
<th scope="col">Created</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@foreach($templates as $template)
|
||||||
|
<tr>
|
||||||
|
<td class="align-middle">
|
||||||
|
<a
|
||||||
|
href="/i/admin/curated-onboarding/templates/edit/{{$template->id}}"
|
||||||
|
class="font-weight-bold">
|
||||||
|
{{ $template->id }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td class="align-middle">
|
||||||
|
{{ $template->name }}
|
||||||
|
</td>
|
||||||
|
<td class="align-middle">
|
||||||
|
{{ str_limit($template->content, 80) }}
|
||||||
|
</td>
|
||||||
|
<td class="align-middle">
|
||||||
|
{{ $template->is_active ? '✅' : '❌' }}
|
||||||
|
</td>
|
||||||
|
<td class="align-middle">
|
||||||
|
{{ $template->created_at->format('M d Y') }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
@endforeach
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<div class="d-flex mt-3">
|
||||||
|
{{ $templates->links() }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@endif
|
||||||
|
|
||||||
|
@endsection
|
|
@ -106,6 +106,12 @@ Route::domain(config('pixelfed.domain.admin'))->prefix('i/admin')->group(functio
|
||||||
Route::get('asf/home', 'AdminShadowFilterController@home');
|
Route::get('asf/home', 'AdminShadowFilterController@home');
|
||||||
Route::redirect('curated-onboarding/', 'curated-onboarding/home');
|
Route::redirect('curated-onboarding/', 'curated-onboarding/home');
|
||||||
Route::get('curated-onboarding/home', 'AdminCuratedRegisterController@index')->name('admin.curated-onboarding');
|
Route::get('curated-onboarding/home', 'AdminCuratedRegisterController@index')->name('admin.curated-onboarding');
|
||||||
|
Route::get('curated-onboarding/templates', 'AdminCuratedRegisterController@templates')->name('admin.curated-onboarding.templates');
|
||||||
|
Route::get('curated-onboarding/templates/create', 'AdminCuratedRegisterController@templateCreate')->name('admin.curated-onboarding.create-template');
|
||||||
|
Route::post('curated-onboarding/templates/create', 'AdminCuratedRegisterController@templateStore');
|
||||||
|
Route::get('curated-onboarding/templates/edit/{id}', 'AdminCuratedRegisterController@templateEdit');
|
||||||
|
Route::post('curated-onboarding/templates/edit/{id}', 'AdminCuratedRegisterController@templateEditStore');
|
||||||
|
Route::delete('curated-onboarding/templates/edit/{id}', 'AdminCuratedRegisterController@templateDelete');
|
||||||
Route::get('curated-onboarding/show/{id}/preview-details-message', 'AdminCuratedRegisterController@previewDetailsMessageShow');
|
Route::get('curated-onboarding/show/{id}/preview-details-message', 'AdminCuratedRegisterController@previewDetailsMessageShow');
|
||||||
Route::get('curated-onboarding/show/{id}/preview-message', 'AdminCuratedRegisterController@previewMessageShow');
|
Route::get('curated-onboarding/show/{id}/preview-message', 'AdminCuratedRegisterController@previewMessageShow');
|
||||||
Route::get('curated-onboarding/show/{id}', 'AdminCuratedRegisterController@show');
|
Route::get('curated-onboarding/show/{id}', 'AdminCuratedRegisterController@show');
|
||||||
|
@ -162,5 +168,6 @@ Route::domain(config('pixelfed.domain.admin'))->prefix('i/admin')->group(functio
|
||||||
Route::post('curated-onboarding/show/{id}/message/send', 'AdminCuratedRegisterController@apiMessageSendStore');
|
Route::post('curated-onboarding/show/{id}/message/send', 'AdminCuratedRegisterController@apiMessageSendStore');
|
||||||
Route::post('curated-onboarding/show/{id}/reject', 'AdminCuratedRegisterController@apiHandleReject');
|
Route::post('curated-onboarding/show/{id}/reject', 'AdminCuratedRegisterController@apiHandleReject');
|
||||||
Route::post('curated-onboarding/show/{id}/approve', 'AdminCuratedRegisterController@apiHandleApprove');
|
Route::post('curated-onboarding/show/{id}/approve', 'AdminCuratedRegisterController@apiHandleApprove');
|
||||||
|
Route::get('curated-onboarding/templates/get', 'AdminCuratedRegisterController@getActiveTemplates');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue