forked from mirror/pixelfed
Merge pull request #4958 from pixelfed/staging
Add Curated Onboarding Templates
This commit is contained in:
commit
8c1e136ce9
|
@ -2,69 +2,72 @@
|
|||
|
||||
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\CuratedRegisterRejectUser;
|
||||
use App\Mail\CuratedRegisterRequestDetailsFromUser;
|
||||
use App\Models\CuratedRegister;
|
||||
use App\Models\CuratedRegisterActivity;
|
||||
use App\Models\CuratedRegisterTemplate;
|
||||
use App\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class AdminCuratedRegisterController extends Controller
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
$this->middleware(['auth','admin']);
|
||||
$this->middleware(['auth', 'admin']);
|
||||
}
|
||||
|
||||
public function index(Request $request)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'filter' => 'sometimes|in:open,all,awaiting,approved,rejected,responses',
|
||||
'sort' => 'sometimes|in:asc,desc'
|
||||
'sort' => 'sometimes|in:asc,desc',
|
||||
]);
|
||||
$filter = $request->input('filter', 'open');
|
||||
$sort = $request->input('sort', 'asc');
|
||||
$records = CuratedRegister::when($filter, function($q, $filter) {
|
||||
if($filter === 'open') {
|
||||
return $q->where('is_rejected', false)
|
||||
->where(function($query) {
|
||||
$records = CuratedRegister::when($filter, function ($q, $filter) {
|
||||
if ($filter === 'open') {
|
||||
return $q->where('is_rejected', false)
|
||||
->where(function ($query) {
|
||||
return $query->where('user_has_responded', true)->orWhere('is_awaiting_more_info', false);
|
||||
})
|
||||
->whereNotNull('email_verified_at')
|
||||
->whereIsClosed(false);
|
||||
} else if($filter === 'all') {
|
||||
return $q;
|
||||
} else if($filter === 'responses') {
|
||||
return $q->whereIsClosed(false)
|
||||
->whereNotNull('email_verified_at')
|
||||
->where('user_has_responded', true)
|
||||
->where('is_awaiting_more_info', true);
|
||||
} elseif ($filter === 'awaiting') {
|
||||
return $q->whereIsClosed(false)
|
||||
->where('is_rejected', false)
|
||||
->where('is_approved', false)
|
||||
->where('user_has_responded', false)
|
||||
->where('is_awaiting_more_info', true);
|
||||
} elseif ($filter === 'approved') {
|
||||
return $q->whereIsClosed(true)->whereIsApproved(true);
|
||||
} elseif ($filter === 'rejected') {
|
||||
return $q->whereIsClosed(true)->whereIsRejected(true);
|
||||
}
|
||||
})
|
||||
->when($sort, function($query, $sort) {
|
||||
} elseif ($filter === 'all') {
|
||||
return $q;
|
||||
} elseif ($filter === 'responses') {
|
||||
return $q->whereIsClosed(false)
|
||||
->whereNotNull('email_verified_at')
|
||||
->where('user_has_responded', true)
|
||||
->where('is_awaiting_more_info', true);
|
||||
} elseif ($filter === 'awaiting') {
|
||||
return $q->whereIsClosed(false)
|
||||
->where('is_rejected', false)
|
||||
->where('is_approved', false)
|
||||
->where('user_has_responded', false)
|
||||
->where('is_awaiting_more_info', true);
|
||||
} elseif ($filter === 'approved') {
|
||||
return $q->whereIsClosed(true)->whereIsApproved(true);
|
||||
} elseif ($filter === 'rejected') {
|
||||
return $q->whereIsClosed(true)->whereIsRejected(true);
|
||||
}
|
||||
})
|
||||
->when($sort, function ($query, $sort) {
|
||||
return $query->orderBy('id', $sort);
|
||||
})
|
||||
->paginate(10)
|
||||
->withQueryString();
|
||||
|
||||
return view('admin.curated-register.index', compact('records', 'filter'));
|
||||
}
|
||||
|
||||
public function show(Request $request, $id)
|
||||
{
|
||||
$record = CuratedRegister::findOrFail($id);
|
||||
|
||||
return view('admin.curated-register.show', compact('record'));
|
||||
}
|
||||
|
||||
|
@ -80,10 +83,10 @@ class AdminCuratedRegisterController extends Controller
|
|||
'message' => null,
|
||||
'link' => null,
|
||||
'timestamp' => $record->created_at,
|
||||
]
|
||||
],
|
||||
]);
|
||||
|
||||
if($record->email_verified_at) {
|
||||
if ($record->email_verified_at) {
|
||||
$res->push([
|
||||
'id' => 3,
|
||||
'action' => 'email_verified_at',
|
||||
|
@ -99,10 +102,11 @@ class AdminCuratedRegisterController extends Controller
|
|||
$idx = 4;
|
||||
$userResponses = collect([]);
|
||||
|
||||
foreach($activities as $activity) {
|
||||
foreach ($activities as $activity) {
|
||||
$idx++;
|
||||
if($activity->from_user) {
|
||||
if ($activity->from_user) {
|
||||
$userResponses->push($activity);
|
||||
|
||||
continue;
|
||||
}
|
||||
$res->push([
|
||||
|
@ -116,20 +120,22 @@ class AdminCuratedRegisterController extends Controller
|
|||
]);
|
||||
}
|
||||
|
||||
foreach($userResponses as $ur) {
|
||||
$res = $res->map(function($r) use($ur) {
|
||||
if(!isset($r['aid'])) {
|
||||
foreach ($userResponses as $ur) {
|
||||
$res = $res->map(function ($r) use ($ur) {
|
||||
if (! isset($r['aid'])) {
|
||||
return $r;
|
||||
}
|
||||
if($ur->reply_to_id === $r['aid']) {
|
||||
if ($ur->reply_to_id === $r['aid']) {
|
||||
$r['user_response'] = $ur;
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
return $r;
|
||||
});
|
||||
}
|
||||
|
||||
if($record->is_approved) {
|
||||
if ($record->is_approved) {
|
||||
$idx++;
|
||||
$res->push([
|
||||
'id' => $idx,
|
||||
|
@ -139,7 +145,7 @@ class AdminCuratedRegisterController extends Controller
|
|||
'link' => null,
|
||||
'timestamp' => $record->action_taken_at,
|
||||
]);
|
||||
} else if ($record->is_rejected) {
|
||||
} elseif ($record->is_rejected) {
|
||||
$idx++;
|
||||
$res->push([
|
||||
'id' => $idx,
|
||||
|
@ -157,13 +163,14 @@ class AdminCuratedRegisterController extends Controller
|
|||
public function apiMessagePreviewStore(Request $request, $id)
|
||||
{
|
||||
$record = CuratedRegister::findOrFail($id);
|
||||
|
||||
return $request->all();
|
||||
}
|
||||
|
||||
public function apiMessageSendStore(Request $request, $id)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'message' => 'required|string|min:5|max:1000'
|
||||
'message' => 'required|string|min:5|max:1000',
|
||||
]);
|
||||
$record = CuratedRegister::findOrFail($id);
|
||||
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->save();
|
||||
Mail::to($record->email)->send(new CuratedRegisterRequestDetailsFromUser($record, $activity));
|
||||
|
||||
return $request->all();
|
||||
}
|
||||
|
||||
|
@ -188,22 +196,23 @@ class AdminCuratedRegisterController extends Controller
|
|||
abort_if($record->email_verified_at === null, 400, 'Cannot message an unverified email');
|
||||
$activity = new CuratedRegisterActivity;
|
||||
$activity->message = $request->input('message');
|
||||
|
||||
return new \App\Mail\CuratedRegisterRequestDetailsFromUser($record, $activity);
|
||||
}
|
||||
|
||||
|
||||
public function previewMessageShow(Request $request, $id)
|
||||
{
|
||||
$record = CuratedRegister::findOrFail($id);
|
||||
abort_if($record->email_verified_at === null, 400, 'Cannot message an unverified email');
|
||||
$record->message = $request->input('message');
|
||||
|
||||
return new \App\Mail\CuratedRegisterSendMessage($record);
|
||||
}
|
||||
|
||||
public function apiHandleReject(Request $request, $id)
|
||||
{
|
||||
$this->validate($request, [
|
||||
'action' => 'required|in:reject-email,reject-silent'
|
||||
'action' => 'required|in:reject-email,reject-silent',
|
||||
]);
|
||||
$action = $request->input('action');
|
||||
$record = CuratedRegister::findOrFail($id);
|
||||
|
@ -212,9 +221,10 @@ class AdminCuratedRegisterController extends Controller
|
|||
$record->is_closed = true;
|
||||
$record->action_taken_at = now();
|
||||
$record->save();
|
||||
if($action === 'reject-email') {
|
||||
if ($action === 'reject-email') {
|
||||
Mail::to($record->email)->send(new CuratedRegisterRejectUser($record));
|
||||
}
|
||||
|
||||
return [200];
|
||||
}
|
||||
|
||||
|
@ -233,10 +243,89 @@ class AdminCuratedRegisterController extends Controller
|
|||
'password' => $record->password,
|
||||
'app_register_ip' => $record->ip_address,
|
||||
'email_verified_at' => now(),
|
||||
'register_source' => 'cur_onboarding'
|
||||
'register_source' => 'cur_onboarding',
|
||||
]);
|
||||
|
||||
Mail::to($record->email)->send(new CuratedRegisterAcceptUser($record));
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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="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="form-group">
|
||||
<label for="requestDetailsMessageInput" class="small text-muted">Your Message:</label>
|
||||
|
@ -60,7 +75,7 @@
|
|||
<p class="help-text small text-right">
|
||||
<span>@{{ composeMessage && composeMessage.length ? composeMessage.length : 0 }}</span>
|
||||
<span>/</span>
|
||||
<span>500</span>
|
||||
<span>2000</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
|
@ -76,6 +91,12 @@
|
|||
target="_blank">
|
||||
Preview
|
||||
</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>
|
||||
|
@ -90,6 +111,21 @@
|
|||
<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>
|
||||
|
||||
<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="form-group">
|
||||
<label for="sendMessageInput" class="small text-muted">Your Message:</label>
|
||||
|
@ -187,11 +223,13 @@
|
|||
messageFormOpen: false,
|
||||
composeMessage: null,
|
||||
messageBody: null,
|
||||
responseTemplates: [],
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
setTimeout(() => {
|
||||
this.fetchResponseTemplates();
|
||||
this.fetchActivities();
|
||||
}, 1000)
|
||||
},
|
||||
|
@ -233,10 +271,16 @@
|
|||
return str;
|
||||
},
|
||||
|
||||
fetchResponseTemplates() {
|
||||
axios.get('/i/admin/api/curated-onboarding/templates/get')
|
||||
.then(res => {
|
||||
this.responseTemplates = res.data;
|
||||
})
|
||||
},
|
||||
|
||||
fetchActivities() {
|
||||
axios.get('/i/admin/api/curated-onboarding/show/{{$id}}/activity-log')
|
||||
.then(res => {
|
||||
console.log(res.data);
|
||||
this.activities = res.data;
|
||||
})
|
||||
.finally(() => {
|
||||
|
@ -379,7 +423,15 @@
|
|||
|
||||
openUserResponse(activity) {
|
||||
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">
|
||||
<ul class="nav nav-pills">
|
||||
<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 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>
|
||||
|
@ -32,6 +32,9 @@
|
|||
<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>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{ request()->is('*templates*') ? 'active' : ''}}" href="/i/admin/curated-onboarding/templates">Templates</a>
|
||||
</li>
|
||||
</ul>
|
||||
</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
|
|
@ -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
|
|
@ -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::redirect('curated-onboarding/', 'curated-onboarding/home');
|
||||
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-message', 'AdminCuratedRegisterController@previewMessageShow');
|
||||
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}/reject', 'AdminCuratedRegisterController@apiHandleReject');
|
||||
Route::post('curated-onboarding/show/{id}/approve', 'AdminCuratedRegisterController@apiHandleApprove');
|
||||
Route::get('curated-onboarding/templates/get', 'AdminCuratedRegisterController@getActiveTemplates');
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue