<?php
namespace FMT\Application\FormType\Admin;
use EasyCorp\Bundle\EasyAdminBundle\Field\BooleanField;
use EasyCorp\Bundle\EasyAdminBundle\Field\ChoiceField;
use EasyCorp\Bundle\EasyAdminBundle\Field\DateTimeField;
use EasyCorp\Bundle\EasyAdminBundle\Field\EmailField;
use EasyCorp\Bundle\EasyAdminBundle\Field\FormField;
use EasyCorp\Bundle\EasyAdminBundle\Field\ImageField;
use EasyCorp\Bundle\EasyAdminBundle\Field\IntegerField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TelephoneField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextareaField;
use EasyCorp\Bundle\EasyAdminBundle\Field\TextField;
use FMT\Application\Controller\Admin\Crud\ExternalUserController;
use FMT\Application\FormType\Admin\Fields\MajorFiled;
use FMT\Application\FormType\RoleType;
use FMT\Application\Validator\Constraints\FmtEmail;
use FMT\Data\Entity\User;
use FMT\Data\Entity\UserProfile;
use FMT\Data\Entity\UserSchool;
use FMT\Data\Repository\UserSchoolRepository;
use FMT\Domain\Repository\UserRepositoryInterface;
use FMT\Domain\Service\Manager\FileManager;
use FMT\Domain\Service\Synchronizer\MajorSynchronizer;
use FMT\Infrastructure\Service\AmazonS3\StorageInterface;
use Generator;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\Range;
use Symfony\Component\Validator\Constraints\Regex;
use FMT\Infrastructure\Helper\CurrencyHelper;
use Symfony\Component\Security\Core\Security;
class ExternalUserCrudType
{
private UserSchoolRepository $userSchoolRepository;
private MajorSynchronizer $majorSynchronizer;
private UserRepositoryInterface $userRepository;
private FileManager $fileManager;
private StorageInterface $avatarStorage;
private array $usStates;
private Security $security;
public function __construct(
UserSchoolRepository $userSchoolRepository,
MajorSynchronizer $majorSynchronizer,
UserRepositoryInterface $userRepository,
FileManager $fileManager,
StorageInterface $avatarStorage,
array $usStates,
Security $security,
) {
$this->userSchoolRepository = $userSchoolRepository;
$this->majorSynchronizer = $majorSynchronizer;
$this->userRepository = $userRepository;
$this->fileManager = $fileManager;
$this->avatarStorage = $avatarStorage;
$this->usStates = $usStates;
$this->security = $security;
}
public function getUserCrudFields(
string $pageName,
StorageInterface $avatarStorage,
?User $user,
string $url
): Generator {
if ($pageName === 'edit') {
return $this->getEditDetailFields($user, $avatarStorage, $url);
}
return $this->getViewFields($avatarStorage, $user, $pageName);
}
/**
* @param StorageInterface $avatarStorage
* @param User|null $user
* @return mixed
*/
private function getViewFields(StorageInterface $avatarStorage, ?User $user, string $pageName)
{
$isStudent = $user instanceof User && $user->isStudent();
$loggedInUser = $this->security->getUser();
$isSchoolAdmin = $loggedInUser->hasRole(User::ROLE_SCHOOL_ADMIN);
yield FormField::addPanel('Personal Info')->onlyOnDetail()->collapsible();
/**
* hide avatar
* */
if(true && ! $isSchoolAdmin){
if ($pageName === 'index' || $isStudent) {
yield ImageField::new('profile.avatar.filename')
->setLabel('fmt.admin_page.user.avatar.name')
->setUploadDir('var')
->setBasePath("/avatar/");
// /->setBasePath($avatarStorage->getBucketUrl())
}
}
yield TextField::new('profile.firstName')
->setLabel('fmt.admin_page.user.form.first_name')
->setSortable(false)
->hideOnForm();
yield TextField::new('profile.lastName')
->setLabel('fmt.admin_page.user.form.last_name')
->setSortable(false)
->hideOnForm();
yield TextField::new('profile.email')
->setLabel('fmt.admin_page.user.form.email')
->setSortable(false)
->hideOnForm();
if(!$isSchoolAdmin){
if ($pageName === 'index' || $isStudent) {
yield TextField::new('profile.school')
->setLabel('fmt.admin_page.user.profile.school.name')
->setSortable(true)
->hideOnForm();
}
if ($pageName === 'index' || $isStudent) {
yield TextField::new('profile.major.name')
->setLabel('fmt.form.major');
//->onlyOnDetail();
}
}
if($pageName === 'index' ){
yield TextField::new('profile.fundedTotal')
->setLabel("Funded")
->formatValue(function ($value, $entity) {
if($entity){
$campaign = $entity->getActiveOrUnstartedCampaign();
if($campaign){
$funded = CurrencyHelper::priceFilter($campaign->getFundedTotal());
return $funded;
}
}
// Fetch data or process logic here
return '-' ;
});
yield TextField::new('profile.transferTotal')
->setLabel("Purchased")
->formatValue(function ($value, $entity) {
if($entity){
$campaign = $entity->getActiveOrUnstartedCampaign();
if($campaign){
$transferred = CurrencyHelper::priceFilter($campaign->getTransferTotal());
return $transferred;
}
}
// Fetch data or process logic here
return '-' ;
});
yield TextField::new('profile.remainingTotal')
->setLabel("Remaining")
->formatValue(function ($value, $entity) {
if($entity){
$campaign = $entity->getActiveOrUnstartedCampaign();
if($campaign){
$remaining = CurrencyHelper::priceFilter($campaign->getRemainingFunds());
return $remaining;
}
}
// Fetch data or process logic here
return '-' ;
});
yield TextField::new('profile.purchaseUrl')
->setLabel("Campaign")
->formatValue(function ($value, $entity) {
if($entity){
$campaign = $entity->getActiveOrUnstartedCampaign();
if($campaign){
$funded = CurrencyHelper::priceFilter($campaign->getFundedTotal());
$transferred = CurrencyHelper::priceFilter($campaign->getTransferTotal());
$remaining = CurrencyHelper::priceFilter($campaign->getRemainingFunds());
return '<a href="/admin?crudAction=edit&crudControllerFqcn=FMT%5CApplication%5CController%5CAdmin%5CCrud%5CCampaignCrudController&entityId=' . $campaign->getId() . '&menuIndex=1&submenuIndex=1&referrer=?crudAction%3Dindex%26crudControllerFqcn%3DFMT%255CApplication%255CController%255CAdmin%255CCrud%255CCampaignCrudController%26entityFqcn%3DFMT%255CApplication%255CController%255CAdmin%255CCampaign%26menuIndex%3D3%26submenuIndex%3D-1&submenuIndex=-1">Purchases/Refunds</a>';
}
}
// Fetch data or process logic here
return '-' ;
});
}
if ($pageName === 'index' && !$isSchoolAdmin){
yield TextField::new('profile.fundedPercent')
->setLabel("% Funded")
->formatValue(function ($value, $entity) {
if($entity){
$campaign = $entity->getActiveOrUnstartedCampaign();
if($campaign){
//return $campaign->estimatedCost();
$total = CurrencyHelper::priceFilter($campaign->getEstimatedCost());
$total = (double)str_replace('$','',$total);
$funded = CurrencyHelper::priceFilter($campaign->getFundedTotal());
$percent = number_format(((double)str_replace('$','',$funded)/$total) * 100,1);
return $percent."%";
}
}
// Fetch data or process logic here
return '-' ;
});
}
if ($isStudent) {
yield BooleanField::new('profile.avatar.status')
->hideWhenCreating()
->setLabel('fmt.admin_page.user.avatar.status')
->onlyOnDetail();
}
if(!$isSchoolAdmin){
yield ChoiceField::new('roles')
->setLabel('fmt.form.roles')
->setChoices(ExternalUserController::EXTERNAL_USER_ROLES)
->setFormType(RoleType::class)
->hideOnForm();
/*
yield DateTimeField::new('lastLogin')
->renderAsText()
->setLabel('fmt.admin_page.user.index.last_login')
->onlyOnIndex();
*/
yield BooleanField::new('enabled')
->setLabel('fmt.form.enabled')
->setTemplatePath('admin/field/boolean.html.twig')
->renderAsSwitch(false)
->hideOnForm();
yield EmailField::new('login')
->setLabel('fmt.user.profile.label.email')
->onlyOnDetail();
if ($isStudent) {
yield TelephoneField::new('profile.phone')
->setLabel('fmt.admin_page.user.form.phone')
->onlyOnDetail();
}
yield TextField::new('profile.snapchatId')
->setLabel('fmt.admin_page.user.form.snapchat')
->onlyOnDetail();
yield TextField::new('profile.facebookMessengerId')
->setLabel('fmt.admin_page.user.form.facebook')
->onlyOnDetail();
yield EmailField::new('profile.otherEmail')
->setLabel('fmt.admin_page.user.form.other')
->onlyOnDetail();
if ($isStudent) {
yield FormField::addPanel('Shipping')
->onlyOnDetail()
->renderCollapsed();
yield TextField::new('profile.address.address1')
->setLabel('fmt.admin_page.user.form.address.line_1')
->onlyOnDetail();
yield TextField::new('profile.address.address2')
->setLabel('fmt.admin_page.user.form.address.line_2')
->onlyOnDetail();
yield TextField::new('profile.address.city')
->setLabel('fmt.admin_page.user.form.address.city')
->onlyOnDetail();
yield TextField::new('profile.address.region')
->setLabel('fmt.admin_page.user.form.address.state')
->onlyOnDetail();
yield TextField::new('profile.address.code')
->setLabel('fmt.admin_page.user.form.address.postal_code')
->onlyOnDetail();
}
yield FormField::addPanel('Visibility')->onlyOnDetail()->renderCollapsed($isStudent);
yield ChoiceField::new('profile.visible')
->setChoices($this->getVisibilityChoices($isStudent))
->setLabel(sprintf('fmt.admin_page.user.form.%s.visible', $isStudent ? 'student' : 'donor'))
->onlyOnDetail();
yield BooleanField::new('profile.facebook')
->setLabel(
sprintf(
'fmt.admin_page.user.form.%s.facebook_enabled',
$isStudent ? 'student' : 'donor'
)
)
->onlyOnDetail();
yield BooleanField::new('profile.twitter')
->setLabel(sprintf('fmt.admin_page.user.form.%s.twitter_enabled', $isStudent ? 'student' : 'donor'))
->onlyOnDetail();
if ($isStudent) {
yield FormField::addPanel('About Me')->renderCollapsed();
yield TextareaField::new('profile.aboutText')->setLabel(false);
}
}
}
/**
* @param User|null $user
* @param StorageInterface $avatarStorage
* @param $url
* @return mixed
*/
public function getEditDetailFields(User $user, StorageInterface $avatarStorage, $url)
{
yield FormField::addPanel('User Settings');
if ($user->isStudent()) {
$originalAvatar = $user->getProfile()->getAvatar();
$previousFile = clone $originalAvatar;
$usrSchoolId = $user->getProfile()->getSchool()->getId();
$majors = $this->majorSynchronizer->synchronizeBySchool($usrSchoolId)->getValues();
yield ImageField::new('profile.avatar.filename')
->setFormTypeOption('upload_new', function (UploadedFile $file) use ($user, $previousFile) {
if ($file) {
$avatarFileName = $this->fileManager->uploadAvatar($user, $file, $previousFile->getFilename());
$user->getProfile()->getAvatar()->setFilename($avatarFileName);
}
})
->setFormTypeOption('upload_delete', function (?File $file) {
if ($file) {
$this->avatarStorage->delete($file->getFilename());
}
})
->setLabel('fmt.admin_page.user.avatar.name')
->setUploadDir('var')
->setBasePath("/avatar")
->setColumns('col-md-5 col-xxl-4');
// /->setBasePath($avatarStorage->getBucketUrl())
yield FormField::addRow();
yield BooleanField::new('profile.avatar.status')
->setTemplatePath('admin/field/boolean.html.twig')
->hideWhenCreating()
->setLabel('fmt.admin_page.user.avatar.status')
->setColumns('col-md-3 col-xxl-2');
}
yield BooleanField::new('enabled')
->setTemplatePath('admin/field/boolean.html.twig')
->hideWhenCreating()
->onlyWhenUpdating()
->setLabel('fmt.form.active')
->addWebpackEncoreEntries('admin_block_user_confirmation')
->setColumns('col-md-3 col-xxl-2');
yield FormField::addRow();
yield FormField::addPanel('Personal Info');
yield TextField::new('profile.firstName')
->setLabel('fmt.admin_page.user.form.first_name')
->setFormTypeOptions([
'required' => true,
'attr' => [
'placeholder' => 'fmt.form.first_name',
],
'constraints' => [
new NotBlank(),
new Length([
'min' => 2,
'max' => 255,
]),
],
])
->setColumns('col-md-3 col-xxl-2')
->setSortable(true);
yield TextField::new('profile.lastName')
->setLabel('fmt.admin_page.user.form.last_name')
->setFormTypeOptions([
'required' => true,
'attr' => [
'placeholder' => 'fmt.form.last_name',
],
'constraints' => [
new NotBlank(),
new Length([
'min' => 2,
'max' => 255,
]),
],
])
->setColumns('col-md-3 col-xxl-2')
->setSortable(true);
yield EmailField::new('login')
->setLabel('fmt.user.profile.label.email')
->setFormTypeOptions([
'required' => true,
'label' => 'fmt.user.profile.label.email',
'attr' => [
'placeholder' => 'fmt.user.profile.email_placeholder',
],
'constraints' => [
new NotBlank(),
new FmtEmail(),
new Length([
'max' => 255,
]),
],
])
->setColumns('col-md-3 col-xxl-2');
if ($user->isStudent()) {
yield TelephoneField::new('profile.phone')
->setLabel('fmt.admin_page.user.form.phone')
->hideOnIndex()
->setFormTypeOptions([
'label' => 'fmt.admin_page.user.form.phone',
'required' => true,
'attr' => [
'placeholder' => 'fmt.admin_page.user.form.phone',
],
'constraints' => [
new NotBlank(),
new Regex([
'pattern' => '/[0-9]{3}-[0-9]{3}-[0-9]{4}/',
'message' => 'fmt.sign_up.phone',
])
],
])
->setColumns('col-md-3 col-xxl-2');
}
yield FormField::addRow();
yield TextField::new('profile.snapchatId')
->setLabel('fmt.admin_page.user.form.snapchat')
->setFormTypeOptions([
'attr' => [
'placeholder' => 'fmt.admin_page.user.form.snapchat',
]
])
->setColumns('col-md-3 col-xxl-2');
yield TextField::new('profile.facebookMessengerId')
->setLabel('fmt.admin_page.user.form.facebook')
->setFormTypeOptions([
'attr' => [
'placeholder' => 'fmt.admin_page.user.form.facebook',
]
])
->setColumns('col-md-3 col-xxl-2');
yield EmailField::new('profile.otherEmail')
->setLabel('fmt.admin_page.user.form.other')
->setFormTypeOptions([
'attr' => [
'placeholder' => 'fmt.user.profile.email_placeholder',
]
])
->setColumns('col-md-3 col-xxl-2');
if ($user->isStudent()) {
yield FormField::addPanel('Shipping');
yield TextField::new('profile.address.address1')
->setRequired(true)
->setLabel('fmt.admin_page.user.form.address.line_1')
->setColumns('col-md-4 col-xxl-3');
yield TextField::new('profile.address.address2')
->setLabel('fmt.admin_page.user.form.address.line_2')
->setColumns('col-md-4 col-xxl-3');
yield FormField::addRow();
yield TextField::new('profile.address.city')
->setRequired(true)
->setLabel('fmt.admin_page.user.form.address.city')
->setColumns('col-md-3 col-xxl-2');
yield ChoiceField::new('profile.address.region')
->setRequired(true)
->setChoices(array_flip($this->usStates))
->setLabel('fmt.admin_page.user.form.address.state')
->setColumns('col-md-3 col-xxl-2');
yield TextField::new('profile.address.code')
->setRequired(true)
->setLabel('fmt.admin_page.user.form.address.postal_code')
->setColumns('col-md-3 col-xxl-2');
yield FormField::addPanel('School');
yield BooleanField::new('profile.firstGen')
->setLabel('fmt.form.first_gen')
->setTemplatePath('admin/field/boolean.html.twig')
->setColumns('col-md-12 col-xxl-12');
yield ChoiceField::new('profile.studentType')
->setLabel('fmt.user.profile.student_type_text') // Field label
->setChoices([
UserProfile::UNDERGRADUATE => UserProfile::UNDERGRADUATE,
UserProfile::GRADUATE => UserProfile::GRADUATE,
])
->setRequired(true) // Make selection mandatory
->renderExpanded(true) // Render as radio buttons
->allowMultipleChoices(false) // Single selection only
->setFormTypeOption('placeholder', 'Select Type'); // Optional placeholder
yield IntegerField::new('profile.gradYear')
->setFormTypeOptions([
'constraints' => [
new NotBlank(),
new Range([
'min' => 1900,
'max' => 3000,
'invalidMessage' => 'fmt.grad_year.error',
'maxMessage' => 'fmt.grad_year.error',
'minMessage' => 'fmt.grad_year.error',
]),
],
])
->setLabel('fmt.form.grad_year')
->setColumns('col-md-2 col-xxl-1');
yield ChoiceField::new('profile.school')
->setChoices($this->userSchoolRepository->getSchoolsCollection($user, true)->toArray())
->setValue($user->getProfile()->getSchool())
->setFormType(EntityType::class)
->setFormTypeOptions(
[
'choice_label' => 'name',
'class' => UserSchool::class,
'attr' => ['data-change' => $url]
]
)
->setFormTypeOption('disabled', !is_null($user->getActiveOrUnstartedCampaign()))
->setLabel('fmt.admin_page.user.profile.school.name')
->setColumns('col-md-3 col-xxl-3')
->setSortable(true);
yield MajorFiled::new('profile.major')
->setDefaultOptions($user)
->setFormTypeOptions(['choices' => $majors])
->setFormTypeOption('disabled', !is_null($user->getActiveOrUnstartedCampaign()))
->setColumns('col-md-3 col-xxl-4');
}
yield FormField::addPanel('Visibility');
yield ChoiceField::new('profile.visible')
->setChoices($this->getVisibilityChoices($user->isStudent()))
->setFormTypeOption('choice_attr', function ($val) {
$visible = ($val == UserProfile::VISIBILITY_NON || $val == UserProfile::VISIBILITY_REGISTRED) ? 'no'
: 'yes';
return ['data-visible' => $visible];
})
->setLabel(sprintf('fmt.admin_page.user.form.%s.visible', $user->isStudent() ? 'student' : 'donor'))
->setColumns('col-md-4 col-xxl-3');
yield FormField::addRow();
yield BooleanField::new('profile.facebook')
->setLabel(
sprintf(
'fmt.admin_page.user.form.%s.facebook_enabled',
$user->isStudent() ? 'student' : 'donor'
)
)
->setTemplatePath('admin/field/boolean.html.twig')
->renderAsSwitch(true)
->hideWhenCreating()
->setColumns('col-md-5 col-xxl-4');
yield BooleanField::new('profile.twitter')
->setLabel(sprintf('fmt.admin_page.user.form.%s.twitter_enabled', $user->isStudent() ? 'student' : 'donor'))
->setTemplatePath('admin/field/boolean.html.twig')
->renderAsSwitch(true)
->hideWhenCreating()
->setColumns('col-md-5 col-xxl-4');
if ($user->isStudent()) {
yield FormField::addPanel('About Me');
yield TextareaField::new('profile.aboutText')
->setFormTypeOptions([
'attr' => [
'rows' => 10,
'maxlength' => 5000,
],
'constraints' => [
new Length([
'max' => 5000,
]),
],
])
->setLabel(false);
}
}
private function getVisibilityChoices(bool $isStudent): array
{
if ($isStudent) {
return array_flip([
UserProfile::VISIBILITY_ALL => 'fmt.user.profile.label.visibility_all',
UserProfile::VISIBILITY_REGISTRED => 'fmt.user.profile.label.visibility_register',
UserProfile::VISIBILITY_NON => 'fmt.user.profile.label.visibility_no',
]);
}
return [
'fmt.user.profile.label.donot_visibility_yes' => UserProfile::VISIBILITY_ALL,
'fmt.user.profile.label.donot_visibility_no' => UserProfile::VISIBILITY_NON
];
}
}