Move the user api_token migration to its original migration, add website and social media columns to the original user migration, hook up user profile edit functionality on the dashboard settings page, name the user password function userPasswordUpdateInit to reflect its form name, clean up the dashboard settings layout and improve it on mobile, add a repeating pattern background to the dashboard so it's not so sparse, and sync the traditional-bootstrap routes/web.php with the main one

This commit is contained in:
Kevin MacMartin 2018-04-25 23:27:45 -04:00
parent 25f65772d5
commit e02d57ad17
10 changed files with 461 additions and 247 deletions

View file

@ -392,6 +392,24 @@ class DashboardController extends Controller {
} }
} }
// User Profile Update
public function postUserProfileUpdate(Request $request)
{
$this->validate($request, [
'name' => 'required|string|max:255'
]);
$user = User::find(Auth::id());
$user->name = $request['name'];
$user->website = $request['website'];
$user->facebook = $request['facebook'];
$user->soundcloud = $request['soundcloud'];
$user->instagram = $request['instagram'];
$user->twitter = $request['twitter'];
$user->save();
return 'success';
}
// User Profile Image Upload // User Profile Image Upload
public function postUserProfileImageUpload(Request $request) public function postUserProfileImageUpload(Request $request)
{ {

View file

@ -15,9 +15,15 @@ class CreateUsersTable extends Migration
{ {
Schema::create('users', function(Blueprint $table) { Schema::create('users', function(Blueprint $table) {
$table->increments('id'); $table->increments('id');
$table->string('name');
$table->string('email')->unique(); $table->string('email')->unique();
$table->string('name');
$table->string('website')->nullable();
$table->string('facebook')->nullable();
$table->string('twitter')->nullable();
$table->string('instagram')->nullable();
$table->string('soundcloud')->nullable();
$table->string('password'); $table->string('password');
$table->string('api_token', 60)->unique();
$table->rememberToken(); $table->rememberToken();
$table->timestamps(); $table->timestamps();
}); });

View file

@ -1,32 +0,0 @@
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class AddApiTokenToUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function(Blueprint $table) {
$table->string('api_token', 60)->unique();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function(Blueprint $table) {
$table->dropColumn('api_token');
});
}
}

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 65.684 65.729"><path d="M65.55 47.072l-23.123-.345L29.035 65.58l-6.817-22.097L.15 36.572l18.909-13.313L18.812.136l18.504 13.87 21.915-7.38-7.473 21.883z" fill-opacity=".949" stroke="#000" stroke-width=".134" stroke-linecap="square" stroke-opacity=".893"/></svg>

After

Width:  |  Height:  |  Size: 314 B

View file

@ -703,8 +703,82 @@ function userProfileImageInit() {
}); });
} }
function userPasswordInit() { function userProfileUpdateInit() {
const $form = $("#user-password"), const $form = $("#user-profile-update"),
$submit = $form.find(".submit-button"),
$inputs = $form.find("input"),
$name = $("#name"),
$website = $("#website"),
$facebook = $("#facebook"),
$soundcloud = $("#soundcloud"),
$instagram = $("#instagram"),
$twitter = $("#twitter"),
$token = $("#token");
let formData = {},
submitting = false;
const getFormData = function() {
formData = {
name: $name.val(),
website: $website.val(),
facebook: $facebook.val(),
soundcloud: $soundcloud.val(),
instagram: $instagram.val(),
twitter: $twitter.val(),
_token: $token.val()
};
};
// remove the error class from an input and enable submit when its value changes
$inputs.on("input change", function() {
$submit.removeClass("no-input");
$(this).removeClass("error");
});
// initialize submit button
$submit.on("click", function() {
if (!submitting) {
submitting = true;
// remove the error class from inputs
$inputs.removeClass("error");
// show the loading modal
showLoadingModal();
// populate the formData object
getFormData();
// submit the update
$.ajax({
type: "POST",
url: "/dashboard/user/profile-update",
data: formData
}).always(function(response) {
hideLoadingModal();
submitting = false;
if (response === "success") {
$submit.addClass("no-input");
showAlert("User profile updated successfully");
} else {
// add the error class to fields that haven't been filled correctly
for (let errorName in response.responseJSON.errors) {
if ($form.find(`[name='${errorName}']`).length) {
$form.find(`[name='${errorName}']`).addClass("error");
}
}
showAlert("Error updating user profile");
}
});
}
});
}
function userPasswordUpdateInit() {
const $form = $("#user-password-update"),
$submit = $form.find(".submit-button"), $submit = $form.find(".submit-button"),
$inputs = $form.find("input"), $inputs = $form.find("input"),
$oldpass = $("#oldpass"), $oldpass = $("#oldpass"),
@ -806,7 +880,11 @@ $(document).ready(function() {
userProfileImageInit(); userProfileImageInit();
} }
if ($("#user-password").length) { if ($("#user-profile-update").length) {
userPasswordInit(); userProfileUpdateInit();
}
if ($("#user-password-update").length) {
userPasswordUpdateInit();
} }
}); });

View file

@ -39,6 +39,7 @@ body {
} }
.site-content { .site-content {
position: relative;
display: flex; display: flex;
min-height: 100vh; min-height: 100vh;
flex-direction: column; flex-direction: column;
@ -48,6 +49,33 @@ body {
} }
} }
.dashboard-background {
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
background-image: url("/img/dashboard/star-bg.svg");
background-position: center top;
background-size: 65px auto;
background-repeat: repeat;
&:after {
content: "";
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
background-color: fade-out(#fff, 0.02);
}
}
.navbar, .dashboard-footer {
z-index: 10;
position: relative;
}
.navbar { .navbar {
margin-bottom: $grid-gutter-width; margin-bottom: $grid-gutter-width;
border: 0; border: 0;
@ -652,10 +680,20 @@ body {
} }
} }
.edit-item { form {
$label-height: 30px;
margin-top: 10px; margin-top: 10px;
.form-title {
@include font-sans-semibold;
margin-top: 0px;
margin-bottom: 15px;
font-size: 14px;
text-transform: uppercase;
}
&.edit-item {
$label-height: 30px;
.CodeMirror { .CodeMirror {
height: 300px; height: 300px;
padding: 5px; padding: 5px;
@ -795,26 +833,30 @@ body {
margin-bottom: 20px; margin-bottom: 20px;
} }
} }
&.no-horizontal-margins {
margin-right: 0px;
margin-left: 0px;
@include media-breakpoint-down(sm) {
width: 100%;
} }
} }
} }
.dashboard-settings-container {
@include media-breakpoint-up(lg) {
display: flex;
flex-direction: row;
}
form {
&.user-profile-image { &.user-profile-image {
display: block; display: block;
width: 100%; width: 100%;
max-width: 150px; max-width: 150px;
@include media-breakpoint-down(sm) { @include media-breakpoint-down(md) {
margin: $grid-gutter-width auto; margin: $grid-gutter-width auto;
} }
@include media-breakpoint-up(lg) {
flex-shrink: 0;
}
.image-display { .image-display {
@include aspect-ratio(1, 1); @include aspect-ratio(1, 1);
position: relative; position: relative;
@ -872,6 +914,52 @@ body {
} }
} }
} }
&.user-profile-update {
@include media-breakpoint-down(md) {
border-top: 1px solid darken($c-dashboard-light, 10%);
border-bottom: 1px solid darken($c-dashboard-light, 10%);
}
@include media-breakpoint-up(lg) {
margin-right: $grid-gutter-width;
margin-left: $grid-gutter-width;
width: 100%;
padding: 0px $grid-gutter-width;
flex-grow: 1;
border-right: 1px solid darken($c-dashboard-light, 10%);
border-left: 1px solid darken($c-dashboard-light, 10%);
}
}
&.user-password-update {
@include media-breakpoint-up(lg) {
width: 225px;
flex-shrink: 0;
}
}
.form-title {
@include media-breakpoint-down(md) {
margin-top: 25px;
margin-bottom: 20px;
text-align: center;
}
}
.submit-button {
@include media-breakpoint-down(sm) {
margin-right: auto;
margin-left: auto;
width: 100%;
}
@include media-breakpoint-up(md) {
float: none;
margin: ($grid-gutter-width / 2) 0px;
}
}
}
} }
#loading-modal { #loading-modal {

View file

@ -7,10 +7,12 @@
<div class="container-fluid"> <div class="container-fluid">
<div class="row"> <div class="row">
<div class="col-12 col-md-8"> <div class="col-12">
<form id="user-profile-image" class="edit-item user-profile-image"> <div class="dashboard-settings-container">
<form id="user-profile-image" class="user-profile-image">
@set('profile_image', $user->profileImage()) @set('profile_image', $user->profileImage())
@set('default_image', App\User::$default_profile_image) @set('default_image', App\User::$default_profile_image)
<h2 class="form-title">Profile Image</h2>
<div <div
class="image-display" class="image-display"
@ -24,16 +26,57 @@
<span id="profile-image-delete" class="image-delete-button {{ $profile_image === null ? 'inactive' : '' }}" title="Delete Profile Image"></span> <span id="profile-image-delete" class="image-delete-button {{ $profile_image === null ? 'inactive' : '' }}" title="Delete Profile Image"></span>
</div> </div>
</form> </form>
<form id="user-profile-update" class="edit-item user-profile-update">
<h2 class="form-title">User Profile</h2>
<label for="email">Email:</label>
<input class="text-input" type="text" name="email" id="email" value="{{ $user->email }}" disabled />
<div class="row">
<div class="col-12 col-md-6">
<label for="name">Name:</label>
<input class="text-input" type="text" name="name" id="name" value="{{ $user->name }}" />
</div> </div>
<div class="col-12 col-md-4"> <div class="col-12 col-md-6">
<form id="user-password" class="edit-item"> <label for="website">Website:</label>
<input class="text-input" type="text" name="website" id="website" value="{{ $user->website }}" />
</div>
<div class="col-12 col-md-6">
<label for="facebook">Facebook URL:</label>
<input class="text-input" type="text" name="facebook" id="facebook" value="{{ $user->facebook }}" />
</div>
<div class="col-12 col-md-6">
<label for="soundcloud">SoundCloud URL:</label>
<input class="text-input" type="text" name="soundcloud" id="soundcloud" value="{{ $user->soundcloud }}" />
</div>
<div class="col-12 col-md-6">
<label for="instagram">Instagram Handle:</label>
<input class="text-input" type="text" name="instagram" id="instagram" value="{{ $user->instagram }}" />
</div>
<div class="col-12 col-md-6">
<label for="twitter">Twitter Handle:</label>
<input class="text-input" type="text" name="twitter" id="twitter" value="{{ $user->twitter }}" />
</div>
</div>
<button type="button" class="submit-button btn btn-primary no-input">Update User Profile</button>
</form>
<form id="user-password-update" class="edit-item user-password-update">
<h2 class="form-title">Update Password</h2>
<input class="text-input" type="password" name="oldpass" id="oldpass" placeholder="Old Password" value="" /> <input class="text-input" type="password" name="oldpass" id="oldpass" placeholder="Old Password" value="" />
<input class="text-input" type="password" name="newpass" id="newpass" placeholder="New Password" value="" /> <input class="text-input" type="password" name="newpass" id="newpass" placeholder="New Password" value="" />
<input class="text-input" type="password" name="newpass_confirmation" id="newpass_confirmation" placeholder="Repeat New Password" value="" /> <input class="text-input" type="password" name="newpass_confirmation" id="newpass_confirmation" placeholder="Repeat New Password" value="" />
<button type="button" class="submit-button no-horizontal-margins btn btn-primary no-input">Update Password</button> <button type="button" class="submit-button btn btn-primary no-input">Update Password</button>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
</div>
@endsection @endsection

View file

@ -8,6 +8,7 @@
@endsection @endsection
@section('page-top') @section('page-top')
<div class="dashboard-background"></div>
@include('dashboard.sections.nav') @include('dashboard.sections.nav')
@endsection @endsection

View file

@ -46,6 +46,7 @@ Route::group([ 'prefix' => 'dashboard' ], function() {
// Dashboard Settings // Dashboard Settings
Route::get('/settings', 'DashboardController@getSettings'); Route::get('/settings', 'DashboardController@getSettings');
Route::post('/user/password-update', 'DashboardController@postUserPasswordUpdate'); Route::post('/user/password-update', 'DashboardController@postUserPasswordUpdate');
Route::post('/user/profile-update', 'DashboardController@postUserProfileUpdate');
Route::post('/user/profile-image-upload', 'DashboardController@postUserProfileImageUpload'); Route::post('/user/profile-image-upload', 'DashboardController@postUserProfileImageUpload');
Route::delete('/user/profile-image-delete', 'DashboardController@deleteUserProfileImageDelete'); Route::delete('/user/profile-image-delete', 'DashboardController@deleteUserProfileImageDelete');

View file

@ -29,19 +29,29 @@ Route::get('/logout', 'Auth\LoginController@logout');
*/ */
Route::group([ 'prefix' => 'dashboard' ], function() { Route::group([ 'prefix' => 'dashboard' ], function() {
// Dashboard CMS
Route::get('/', 'DashboardController@getIndex'); Route::get('/', 'DashboardController@getIndex');
Route::get('/credits', 'DashboardController@getCredits');
Route::get('/view/{model}', 'DashboardController@getView'); Route::get('/view/{model}', 'DashboardController@getView');
Route::get('/edit/{model}', 'DashboardController@getEditList'); Route::get('/edit/{model}', 'DashboardController@getEditList');
Route::get('/edit/{model}/{id}', 'DashboardController@getEditItem'); Route::get('/edit/{model}/{id}', 'DashboardController@getEditItem');
Route::get('/export/{model}', 'DashboardController@getExport'); Route::get('/export/{model}', 'DashboardController@getExport');
Route::post('/reorder', 'DashboardController@postReorder');
Route::post('/update', 'DashboardController@postUpdate');
Route::post('/image-upload', 'DashboardController@postImageUpload'); Route::post('/image-upload', 'DashboardController@postImageUpload');
Route::post('/file-upload', 'DashboardController@postFileUpload'); Route::post('/file-upload', 'DashboardController@postFileUpload');
Route::post('/update', 'DashboardController@postUpdate');
Route::post('/reorder', 'DashboardController@postReorder');
Route::delete('/delete', 'DashboardController@deleteDelete'); Route::delete('/delete', 'DashboardController@deleteDelete');
Route::delete('/image-delete', 'DashboardController@deleteImageDelete'); Route::delete('/image-delete', 'DashboardController@deleteImageDelete');
Route::delete('/file-delete', 'DashboardController@deleteFileDelete'); Route::delete('/file-delete', 'DashboardController@deleteFileDelete');
// Dashboard Settings
Route::get('/settings', 'DashboardController@getSettings');
Route::post('/user/password-update', 'DashboardController@postUserPasswordUpdate');
Route::post('/user/profile-update', 'DashboardController@postUserProfileUpdate');
Route::post('/user/profile-image-upload', 'DashboardController@postUserProfileImageUpload');
Route::delete('/user/profile-image-delete', 'DashboardController@deleteUserProfileImageDelete');
// Credits Page
Route::get('/credits', 'DashboardController@getCredits');
}); });
/* /*