Skip to content

Commit

Permalink
Added user settings page
Browse files Browse the repository at this point in the history
  • Loading branch information
simba77 committed Dec 16, 2021
1 parent 3015470 commit 8922c42
Show file tree
Hide file tree
Showing 9 changed files with 263 additions and 114 deletions.
4 changes: 4 additions & 0 deletions modules/johncms/personal/config/routes.php
Expand Up @@ -11,6 +11,7 @@
use Johncms\Auth\Middlewares\AuthorizedUserMiddleware;
use Johncms\Personal\Controllers\PersonalController;
use Johncms\Personal\Controllers\ProfileController;
use Johncms\Personal\Controllers\SettingsController;
use League\Route\RouteGroup;
use League\Route\Router;

Expand All @@ -20,5 +21,8 @@
$route->get('/profile[/[{id:number}[/]]]', [ProfileController::class, 'index'])->setName('personal.profile');
$route->get('/profile/edit/{id:number}[/]', [ProfileController::class, 'edit'])->setName('personal.profile.edit');
$route->post('/profile/store/{id:number}[/]', [ProfileController::class, 'store'])->setName('personal.profile.store');

$route->get('/settings[/]', [SettingsController::class, 'index'])->setName('personal.settings');
$route->post('/settings/store[/]', [SettingsController::class, 'store'])->setName('personal.settings.store');
})->lazyMiddleware(AuthorizedUserMiddleware::class);
};
78 changes: 78 additions & 0 deletions modules/johncms/personal/src/Controllers/SettingsController.php
@@ -0,0 +1,78 @@
<?php

/**
* This file is part of JohnCMS Content Management System.
*
* @copyright JohnCMS Community
* @license https://opensource.org/licenses/GPL-3.0 GPL-3.0
* @link https://johncms.com JohnCMS Project
*/

declare(strict_types=1);

namespace Johncms\Personal\Controllers;

use Johncms\Controller\BaseController;
use Johncms\Exceptions\ValidationException;
use Johncms\Http\Response\RedirectResponse;
use Johncms\Http\Session;
use Johncms\Personal\Forms\SettingsForm;
use Johncms\Users\Exceptions\RuntimeException;
use Johncms\Users\User;
use Johncms\Users\UserManager;
use Psr\Http\Message\ResponseInterface;
use Throwable;

class SettingsController extends BaseController
{
protected string $moduleName = 'johncms/personal';

public function __construct()
{
parent::__construct();
$this->metaTagManager->setAll(__('User Profile'));
$this->navChain->add(__('Personal account'), route('personal.index'));
$this->navChain->add(__('Settings'), route('personal.settings'));
}

/**
* @throws Throwable
*/
public function index(SettingsForm $settingsForm, Session $session): string|ResponseInterface
{
return $this->render->render('personal::settings', [
'data' => [
'formFields' => $settingsForm->getFormFields(),
'validationErrors' => $settingsForm->getValidationErrors(),
'success' => $session->getFlash('success'),
'errors' => $session->getFlash('errors'),
'storeUrl' => route('personal.settings.store'),
'backButton' => route('personal.index'),
],
]);
}

/**
* @throws Throwable
*/
public function store(SettingsForm $settingsForm, User $user, UserManager $userManager, Session $session): ResponseInterface|RedirectResponse
{
try {
// Validate the form
$settingsForm->validate();
try {
$userManager->update($user->id, ['settings' => $settingsForm->getRequestValues()]);
$session->flash('success', __('Settings saved successfully'));
return new RedirectResponse(route('personal.settings'));
} catch (RuntimeException $exception) {
$session->flash('errors', $exception->getMessage());
return (new RedirectResponse(route('personal.settings')))->withPost();
}
} catch (ValidationException $validationException) {
// Redirect if the form is invalid
return (new RedirectResponse(route('personal.settings')))
->withPost()
->withValidationErrors($validationException->getErrors());
}
}
}
120 changes: 120 additions & 0 deletions modules/johncms/personal/src/Forms/SettingsForm.php
@@ -0,0 +1,120 @@
<?php

declare(strict_types=1);

namespace Johncms\Personal\Forms;

use Johncms\Forms\AbstractForm;
use Johncms\Forms\Inputs\Checkbox;
use Johncms\Forms\Inputs\InputText;
use Johncms\Forms\Inputs\Select;
use Johncms\i18n\Languages;
use Johncms\Users\User;
use Johncms\View\Themes;

class SettingsForm extends AbstractForm
{
public function __construct(
protected ?User $userData = null
) {
parent::__construct();
}

/**
* @inheritDoc
*/
protected function prepareFormFields(): array
{
$fields = [];
$fields['lang'] = (new Select())
->setOptions($this->getLanguages())
->setLabel(__('Language'))
->setNameAndId('lang')
->setValue($this->getValue('lang'));

$fields['timezone'] = (new Select())
->setOptions($this->getTimezones())
->setLabel(__('Timezone'))
->setNameAndId('timezone')
->setValue($this->getValue('timezone'));

$fields['directUrl'] = (new Checkbox())
->setLabel(__('Direct links'))
->setNameAndId('directUrl')
->setHelpText(__('When this option is enabled, links to other sites will open without an intermediate page.'))
->setValue(true)
->setChecked((bool) $this->getValue('directUrl'));

$fields['perPage'] = (new InputText())
->setLabel(__('Elements per page'))
->setPlaceholder(__('Elements per page'))
->setNameAndId('perPage')
->setValue($this->getValue('perPage'));

$fields['theme'] = (new Select())
->setOptions($this->getThemesList())
->setLabel(__('Site theme'))
->setNameAndId('theme')
->setValue($this->getValue('theme'));

return $fields;
}

public function getValue(string $fieldName, mixed $default = null)
{
if ($this->userData) {
// Base fields
return parent::getValue($fieldName, $this->userData->settings?->$fieldName);
}
return parent::getValue($fieldName, $default);
}

private function getThemesList(): array
{
$themes = di(Themes::class)->getThemes();
$themesList = [];
foreach ($themes as $theme) {
if ($theme === 'example') {
continue;
}
$themesList[] = [
'name' => $theme,
'value' => $theme,
];
}
return $themesList;
}

// TODO: Change the list of timezones
private function getTimezones(): array
{
return [
[
'value' => 'Europe/Moscow',
'name' => d__('system', 'Europe/Moscow'),
],
[
'value' => 'Europe/Berlin',
'name' => d__('system', 'Europe/Berlin'),
],
[
'value' => 'America/New_York',
'name' => d__('system', 'America/New_York'),
],
];
}

private function getLanguages(): array
{
$lngList = Languages::getLngList();
$options = [];
foreach ($lngList as $key => $item) {
$options[] = [
'name' => $item['name'],
'value' => $key,
];
}

return $options;
}
}
2 changes: 1 addition & 1 deletion modules/johncms/personal/templates/index.phtml
Expand Up @@ -23,7 +23,7 @@ $this->layout('system::layout/default');
</a>
</div>
<div class="col mb-2">
<a href="" class="card text-center">
<a href="<?= route('personal.settings') ?>" class="card text-center">
<div class="card-body">
<div class="icon_with_badge d-inline-block">
<svg class="icon-40">
Expand Down
122 changes: 14 additions & 108 deletions modules/johncms/personal/templates/settings.phtml
@@ -1,120 +1,26 @@
<?php

/**
* This file is part of JohnCMS Content Management System.
*
* @copyright JohnCMS Community
* @license https://opensource.org/licenses/GPL-3.0 GPL-3.0
* @link https://johncms.com JohnCMS Project
*/

/**
* @var $title
* @var $page_title
* @var $data
*/

$this->layout(
'system::layout/default',
[
'title' => $title,
'page_title' => $title,
]
);

$userConfig = $user->config;

$this->layout('system::layout/default');
?>

<div class="buttons mb-2">
<?php foreach ($data['buttons'] as $button): ?>
<a href="<?= $button['url'] ?>" class="btn btn-outline-primary mb-1 <?= $button['active'] ? 'active' : '' ?>"><?= $button['name'] ?></a>
<?php endforeach; ?>
</div>

<?php if (! empty($data['success_message'])): ?>
<form method="post" class="mb-3" action="<?= $data['storeUrl'] ?>">
<?php if (! empty($data['success'])): ?>
<?= $this->fetch('system::app/alert', ['alert_type' => 'alert-success', 'alert' => $data['success']]) ?>
<?php endif ?>
<?php if (! empty($data['errors'])): ?>
<?= $this->fetch('system::app/alert', ['alert_type' => 'alert-danger', 'alert' => $data['errors']]) ?>
<?php endif ?>
<?= $this->fetch(
'system::app/alert',
'system::forms/simple_form',
[
'alert_type' => 'alert-success',
'alert' => $data['success_message'],
'fields' => $data['formFields'],
'errors' => $data['validationErrors'],
]
) ?>
<?php endif; ?>
<form action="<?= $data['form_action'] ?>" method="post">
<h3><?= __('Time settings') ?></h3>
<div class="form-group">
<label for="timeshift"><?= __('Shift of time') ?> (+-12)</label>
<input type="text"
class="form-control"
name="timeshift"
id="timeshift"
size="2"
maxlength="3"
value="<?= $userConfig->timeshift ?>"
placeholder="<?= __('Shift of time') ?>"
>
<div class="small text-muted">
<?= __('System time') ?>: <?= $data['system_time'] ?>
</div>
</div>

<h3><?= __('System Functions') ?></h3>
<div class="custom-control custom-checkbox">
<input type="checkbox" class="form-check-input" name="directUrl" value="1" id="directUrl" <?= $userConfig->directUrl ? 'checked' : '' ?>>
<label class="form-check-label" for="directUrl"><?= __('Direct URL') ?></label>
</div>
<div class="custom-control custom-checkbox mb-3">
<input type="checkbox" class="form-check-input" name="youtube" value="1" id="youtube" <?= $userConfig->youtube ? 'checked' : '' ?>>
<label class="form-check-label" for="youtube"><?= __('Youtube Player') ?></label>
</div>

<h3><?= __('Text entering') ?></h3>
<div class="form-group">
<label for="fieldHeight"><?= __('Height of field') ?> (1-9)</label>
<input type="text"
class="form-control"
name="fieldHeight"
id="fieldHeight"
maxlength="1"
value="<?= $userConfig->fieldHeight ?>"
placeholder="<?= __('Height of field') ?>"
>
</div>

<h3><?= __('Appearance') ?></h3>
<div class="form-group">
<label for="kmess"><?= __('Size of Lists') ?> (5-99)</label>
<input type="text"
class="form-control"
name="kmess"
id="kmess"
maxlength="2"
value="<?= $userConfig->kmess ?>"
placeholder="<?= __('Size of Lists') ?>"
>
</div>

<?php if (! empty($data['lng_list'])): ?>
<h3><?= __('Select Language') ?></h3>
<div class="form-group">
<label for="iso"><?= __('Select Language') ?></label>
<select class="form-control" id="iso" name="iso">
<?php foreach ($data['lng_list'] as $key => $lang): ?>
<option value="<?= $key ?>"
<?= ($key === $data['user_lng'] || ($key === $config['lng'] && empty($data['user_lng']))) ? 'selected' : '' ?>
><?= $lang['name'] ?><?= ($key === $config['lng'] ? ' (' . __('Site Default') . ')' : '') ?></option>
<?php endforeach; ?>
</select>
</div>
<?php endif; ?>
<div class="d-flex flex-wrap justify-content-between">
<div class="mb-1 me-1">
<input type="submit" name="submit" value="<?= __('Save') ?>" class="btn btn-primary"/>
<a href="?act=office" class="btn btn-secondary"><?= __('Cancel') ?></a>
</div>
<div>
<a href="?act=settings&amp;reset" class="btn btn-danger"><?= __('Reset Settings') ?></a>
</div>
</div>
); ?>
<button type="submit" name="submit" class="btn btn-primary"><?= __('Save') ?></button>
<a href="<?= $data['backButton'] ?>" class="btn btn-outline-secondary"><?= __('Back') ?></a>
</form>
20 changes: 19 additions & 1 deletion system/src/Users/UserConfig.php
Expand Up @@ -23,10 +23,28 @@ class UserConfig

public string $timezone = 'UTC';

public ?string $theme = null;

public function __construct(array $settings = [])
{
foreach ($settings as $key => $value) {
$this->$key = $value;
$this->$key = $this->castValue(gettype($this->$key), $value);
}
}

/**
* @param string $type
* @param mixed $value
* @return bool|float|int|string
*/
private function castValue(string $type, mixed $value): float|bool|int|string
{
return match ($type) {
'int', 'integer' => (int) $value,
'float' => (float) $value,
'string' => (string) $value,
'bool', 'boolean' => (bool) $value,
default => $value,
};
}
}

0 comments on commit 8922c42

Please sign in to comment.