chore: sync module from working instance and add install guide
This commit is contained in:
55
INSTALL.md
Normal file
55
INSTALL.md
Normal file
@@ -0,0 +1,55 @@
|
||||
# Animal Management Installation Guide
|
||||
|
||||
This guide installs the `animal_management` module in a reusable way for any HumHub instance.
|
||||
|
||||
## 1. Requirements
|
||||
|
||||
- HumHub `1.14+`
|
||||
- Module directory access on the target instance
|
||||
- Optional but recommended: `rescue_foundation` module
|
||||
|
||||
## 2. Clone into HumHub Modules Directory
|
||||
|
||||
The folder name must be exactly `animal_management`.
|
||||
|
||||
```bash
|
||||
git clone https://gitea.kelinreij.duckdns.org/humhub-modules/animal-management.git \
|
||||
/var/www/localhost/htdocs/protected/modules/animal_management
|
||||
```
|
||||
|
||||
If the folder already exists:
|
||||
|
||||
```bash
|
||||
cd /var/www/localhost/htdocs/protected/modules/animal_management
|
||||
git pull
|
||||
```
|
||||
|
||||
## 3. Enable the Module
|
||||
|
||||
In HumHub UI:
|
||||
|
||||
1. Go to `Administration` -> `Modules`.
|
||||
2. Enable `Animal Management`.
|
||||
3. Enable it per space where needed.
|
||||
|
||||
## 4. Run Migrations
|
||||
|
||||
From the HumHub app host/container:
|
||||
|
||||
```bash
|
||||
php /var/www/localhost/htdocs/protected/yii migrate/up \
|
||||
--include-module-migrations=1 --interactive=0
|
||||
```
|
||||
|
||||
## 5. Verify
|
||||
|
||||
1. Open a space where the module is enabled.
|
||||
2. Confirm Animals views load.
|
||||
3. Confirm medical/progress/transfer flows render without errors.
|
||||
|
||||
## Docker Example
|
||||
|
||||
```bash
|
||||
docker exec humhub php /var/www/localhost/htdocs/protected/yii migrate/up \
|
||||
--include-module-migrations=1 --interactive=0
|
||||
```
|
||||
@@ -42,6 +42,8 @@ class AnimalsController extends ContentContainerController
|
||||
'add-medical-visit' => ['post'],
|
||||
'add-progress-update' => ['post'],
|
||||
'add-gallery-images' => ['post'],
|
||||
'add-gallery-images-inline' => ['get', 'post'],
|
||||
'transfer-inline' => ['get', 'post'],
|
||||
'remove-gallery-image' => ['post'],
|
||||
'transfer-respond' => ['post'],
|
||||
'transfer-complete' => ['post'],
|
||||
@@ -55,7 +57,7 @@ class AnimalsController extends ContentContainerController
|
||||
protected function getAccessRules()
|
||||
{
|
||||
return [
|
||||
[ContentContainerControllerAccess::RULE_USER_GROUP_ONLY => [Space::USERGROUP_OWNER, Space::USERGROUP_ADMIN, Space::USERGROUP_MODERATOR], 'actions' => ['create', 'edit', 'delete', 'transfer', 'add-medical-visit', 'add-medical-visit-inline', 'edit-medical-visit', 'add-progress-update', 'add-progress-update-inline', 'edit-progress-update', 'add-gallery-images', 'remove-gallery-image', 'transfer-respond', 'transfer-complete', 'transfer-cancel']],
|
||||
[ContentContainerControllerAccess::RULE_USER_GROUP_ONLY => [Space::USERGROUP_OWNER, Space::USERGROUP_ADMIN, Space::USERGROUP_MODERATOR], 'actions' => ['create', 'edit', 'delete', 'transfer', 'transfer-inline', 'add-medical-visit', 'add-medical-visit-inline', 'edit-medical-visit', 'add-progress-update', 'add-progress-update-inline', 'edit-progress-update', 'add-gallery-images', 'add-gallery-images-inline', 'remove-gallery-image', 'transfer-respond', 'transfer-complete', 'transfer-cancel']],
|
||||
];
|
||||
}
|
||||
|
||||
@@ -68,9 +70,13 @@ class AnimalsController extends ContentContainerController
|
||||
GalleryIntegrationService::syncSpaceAnimalGalleries($this->contentContainer);
|
||||
}
|
||||
$viewMode = trim((string)Yii::$app->request->get('view', 'tiles'));
|
||||
if (!in_array($viewMode, ['tiles', 'table'], true)) {
|
||||
if (!in_array($viewMode, ['tiles', 'tiles2', 'rows', 'tablet', 'table'], true)) {
|
||||
$viewMode = 'tiles';
|
||||
}
|
||||
$isFocusModeRequest = trim((string)Yii::$app->request->get('focus', '')) === '1';
|
||||
if ($isFocusModeRequest) {
|
||||
$viewMode = 'tablet';
|
||||
}
|
||||
|
||||
$sortKey = trim((string)Yii::$app->request->get('sort', 'updated_at'));
|
||||
$sortDirection = strtolower(trim((string)Yii::$app->request->get('direction', 'desc'))) === 'asc' ? 'asc' : 'desc';
|
||||
@@ -165,6 +171,33 @@ class AnimalsController extends ContentContainerController
|
||||
return (int)$animal->id;
|
||||
}, $animals);
|
||||
|
||||
$animalDonationGoalsByAnimal = [];
|
||||
$donationGoalClass = 'humhub\\modules\\donations\\models\\DonationGoal';
|
||||
if (!empty($animalIds)
|
||||
&& $this->contentContainer instanceof Space
|
||||
&& $this->contentContainer->moduleManager->isEnabled('donations')
|
||||
&& class_exists($donationGoalClass)
|
||||
&& Yii::$app->db->schema->getTableSchema($donationGoalClass::tableName(), true) !== null
|
||||
) {
|
||||
$donationGoals = $donationGoalClass::find()
|
||||
->where([
|
||||
'contentcontainer_id' => $this->contentContainer->contentcontainer_id,
|
||||
'goal_type' => $donationGoalClass::TYPE_ANIMAL,
|
||||
])
|
||||
->andWhere(['target_animal_id' => $animalIds])
|
||||
->orderBy(['is_active' => SORT_DESC, 'id' => SORT_DESC])
|
||||
->all();
|
||||
|
||||
foreach ($donationGoals as $goal) {
|
||||
$animalId = (int)$goal->target_animal_id;
|
||||
if ($animalId <= 0 || isset($animalDonationGoalsByAnimal[$animalId])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$animalDonationGoalsByAnimal[$animalId] = $goal;
|
||||
}
|
||||
}
|
||||
|
||||
$animalImageUrls = $this->resolveAnimalImageUrls($animalIds, ['profile_image_url', 'profile_image', 'photo_url', 'image_url', 'photo'], false);
|
||||
$tileFieldOverrides = $this->resolveDisplayFieldOverrides($animalIds, 'tile_display_fields');
|
||||
|
||||
@@ -245,6 +278,7 @@ class AnimalsController extends ContentContainerController
|
||||
'animalImageUrls' => $animalImageUrls,
|
||||
'tileFields' => $this->getTileFieldSettings(),
|
||||
'tileFieldOverrides' => $tileFieldOverrides,
|
||||
'animalDonationGoalsByAnimal' => $animalDonationGoalsByAnimal,
|
||||
'space' => $this->contentContainer,
|
||||
'canManage' => $this->canManageAnimals(),
|
||||
'incomingTransfers' => $incomingTransfers,
|
||||
@@ -257,6 +291,10 @@ class AnimalsController extends ContentContainerController
|
||||
{
|
||||
$animal = $this->findAnimal($id);
|
||||
$canManage = $this->canManageAnimals();
|
||||
$layoutMode = trim((string)Yii::$app->request->get('layout', 'default'));
|
||||
if (!in_array($layoutMode, ['default', 'tablet'], true)) {
|
||||
$layoutMode = 'default';
|
||||
}
|
||||
|
||||
if ($this->contentContainer instanceof Space) {
|
||||
GalleryIntegrationService::ensureAnimalGallery($animal, $this->contentContainer);
|
||||
@@ -279,8 +317,10 @@ class AnimalsController extends ContentContainerController
|
||||
$transferEvents = $animal->getTransferEvents()->orderBy(['id' => SORT_DESC])->limit(100)->all();
|
||||
$galleryItems = $animal->getGalleryItems()->orderBy(['id' => SORT_DESC])->limit(120)->all();
|
||||
$customFieldValues = $animal->getCustomFieldDisplayValues($canManage);
|
||||
$animalImageUrls = $this->resolveAnimalImageUrls([(int)$animal->id], ['cover_image_url', 'image_url', 'photo_url', 'photo'], false);
|
||||
$animalCoverImageUrl = trim((string)($animalImageUrls[(int)$animal->id] ?? ''));
|
||||
$animalCoverImageUrls = $this->resolveAnimalImageUrls([(int)$animal->id], ['cover_image_url', 'image_url', 'photo_url', 'photo'], false);
|
||||
$animalProfileImageUrls = $this->resolveAnimalImageUrls([(int)$animal->id], ['profile_image_url', 'profile_image', 'image_url', 'photo_url', 'photo'], false);
|
||||
$animalCoverImageUrl = trim((string)($animalCoverImageUrls[(int)$animal->id] ?? ''));
|
||||
$animalProfileImageUrl = trim((string)($animalProfileImageUrls[(int)$animal->id] ?? ''));
|
||||
$detailHeroFields = $this->getDetailHeroFieldSettings();
|
||||
$heroOverrides = $this->resolveDisplayFieldOverrides([(int)$animal->id], 'hero_display_fields');
|
||||
if (!empty($heroOverrides[(int)$animal->id])) {
|
||||
@@ -298,7 +338,9 @@ class AnimalsController extends ContentContainerController
|
||||
'galleryItems' => $galleryItems,
|
||||
'customFieldValues' => $customFieldValues,
|
||||
'animalCoverImageUrl' => $animalCoverImageUrl,
|
||||
'animalProfileImageUrl' => $animalProfileImageUrl,
|
||||
'detailHeroFields' => $detailHeroFields,
|
||||
'layoutMode' => $layoutMode,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -352,6 +394,7 @@ class AnimalsController extends ContentContainerController
|
||||
public function actionCreate()
|
||||
{
|
||||
$model = new AnimalForm(['contentContainer' => $this->contentContainer]);
|
||||
$intakeGoalPayload = (array)Yii::$app->request->post('IntakeGoal', []);
|
||||
|
||||
if (Yii::$app->request->isPost) {
|
||||
$model->load(Yii::$app->request->post());
|
||||
@@ -368,6 +411,11 @@ class AnimalsController extends ContentContainerController
|
||||
if ($this->contentContainer instanceof Space) {
|
||||
GalleryIntegrationService::ensureAnimalGallery($savedAnimal, $this->contentContainer);
|
||||
}
|
||||
|
||||
$goalError = $this->createIntakeAnimalGoal($savedAnimal, $intakeGoalPayload);
|
||||
if ($goalError !== null) {
|
||||
$this->view->error($goalError);
|
||||
}
|
||||
}
|
||||
|
||||
$this->view->success(Yii::t('AnimalManagementModule.base', 'Animal created.'));
|
||||
@@ -379,6 +427,7 @@ class AnimalsController extends ContentContainerController
|
||||
'space' => $this->contentContainer,
|
||||
'isEdit' => false,
|
||||
'animal' => null,
|
||||
'showIntakeGoalSection' => $this->canUseIntakeGoalSection(),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -460,6 +509,7 @@ class AnimalsController extends ContentContainerController
|
||||
public function actionTransfer(int $id)
|
||||
{
|
||||
$animal = $this->findAnimal($id);
|
||||
$returnTo = (string)Yii::$app->request->post('returnTo', Yii::$app->request->get('returnTo', 'view'));
|
||||
|
||||
$form = new TransferRequestForm([
|
||||
'animal' => $animal,
|
||||
@@ -468,107 +518,74 @@ class AnimalsController extends ContentContainerController
|
||||
|
||||
if ($form->load(Yii::$app->request->post()) && $form->save()) {
|
||||
$this->view->success(Yii::t('AnimalManagementModule.base', 'Transfer request sent.'));
|
||||
return $this->redirect($this->contentContainer->createUrl('/animal_management/animals/view', ['id' => $animal->id]));
|
||||
return $this->redirectToAnimalPage((int)$animal->id, $returnTo);
|
||||
}
|
||||
|
||||
return $this->render('transfer', [
|
||||
'space' => $this->contentContainer,
|
||||
'animal' => $animal,
|
||||
'model' => $form,
|
||||
'isInline' => false,
|
||||
'returnTo' => $returnTo,
|
||||
]);
|
||||
}
|
||||
|
||||
public function actionTransferInline(int $id)
|
||||
{
|
||||
$animal = $this->findAnimal($id);
|
||||
$returnTo = (string)Yii::$app->request->post('returnTo', Yii::$app->request->get('returnTo', 'view'));
|
||||
$isInline = (int)Yii::$app->request->get('inline', 1) === 1;
|
||||
|
||||
$form = new TransferRequestForm([
|
||||
'animal' => $animal,
|
||||
'sourceSpace' => $this->contentContainer,
|
||||
]);
|
||||
|
||||
if ($form->load(Yii::$app->request->post()) && $form->save()) {
|
||||
$this->view->success(Yii::t('AnimalManagementModule.base', 'Transfer request sent.'));
|
||||
if ($isInline) {
|
||||
return $this->renderAjax('inline-edit-result', [
|
||||
'collapseId' => 'transfer-add-inline',
|
||||
'refreshSelectors' => ['#animal-transfer-panel'],
|
||||
]);
|
||||
}
|
||||
return $this->redirectToAnimalPage((int)$animal->id, $returnTo);
|
||||
}
|
||||
|
||||
$params = [
|
||||
'space' => $this->contentContainer,
|
||||
'animal' => $animal,
|
||||
'model' => $form,
|
||||
'isInline' => $isInline,
|
||||
'returnTo' => $returnTo,
|
||||
];
|
||||
|
||||
if ($isInline) {
|
||||
return $this->renderAjax('transfer', $params);
|
||||
}
|
||||
|
||||
return $this->render('transfer', $params);
|
||||
}
|
||||
|
||||
public function actionAddGalleryImages(int $id)
|
||||
{
|
||||
$animal = $this->findAnimal($id);
|
||||
$uploadedFiles = UploadedFile::getInstancesByName('galleryImages');
|
||||
$maxUploadCount = 10;
|
||||
$result = $this->processGalleryUploads($animal);
|
||||
|
||||
if (empty($uploadedFiles)) {
|
||||
if (!$result['hadSelection']) {
|
||||
$this->view->error(Yii::t('AnimalManagementModule.base', 'No gallery images were selected.'));
|
||||
return $this->redirect($this->contentContainer->createUrl('/animal_management/animals/view', ['id' => $animal->id]) . '#animal-gallery');
|
||||
}
|
||||
|
||||
if (count($uploadedFiles) > $maxUploadCount) {
|
||||
$uploadedFiles = array_slice($uploadedFiles, 0, $maxUploadCount);
|
||||
$this->view->info(Yii::t('AnimalManagementModule.base', 'Only the first {count} selected images were processed.', ['count' => $maxUploadCount]));
|
||||
if ($result['wasLimited']) {
|
||||
$this->view->info(Yii::t('AnimalManagementModule.base', 'Only the first {count} selected images were processed.', ['count' => $result['maxUploadCount']]));
|
||||
}
|
||||
|
||||
$allowedExtensions = array_map('strtolower', UploadStandards::imageExtensions());
|
||||
$allowedMimeTypes = array_map('strtolower', UploadStandards::imageMimeTypes());
|
||||
$maxBytes = (int)UploadStandards::IMAGE_MAX_BYTES;
|
||||
$existingItems = AnimalGalleryItem::find()->where(['animal_id' => (int)$animal->id])->all();
|
||||
$existingHashes = [];
|
||||
foreach ($existingItems as $existingItem) {
|
||||
$existingUrl = trim((string)$existingItem->getImageUrl());
|
||||
if ($existingUrl === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$hash = $this->computeImageContentHash($existingUrl);
|
||||
if ($hash !== null) {
|
||||
$existingHashes[$hash] = true;
|
||||
}
|
||||
}
|
||||
|
||||
$added = 0;
|
||||
foreach ($uploadedFiles as $uploadedFile) {
|
||||
if (!$uploadedFile instanceof UploadedFile) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$extension = strtolower((string)$uploadedFile->extension);
|
||||
$mimeType = strtolower((string)$uploadedFile->type);
|
||||
|
||||
if (!in_array($extension, $allowedExtensions, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($mimeType !== '' && !in_array($mimeType, $allowedMimeTypes, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($uploadedFile->size > $maxBytes) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$storedPath = $this->storeGalleryUpload($animal, $uploadedFile);
|
||||
if ($storedPath === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$storedHash = $this->computeImageContentHash($storedPath);
|
||||
|
||||
$exactExists = AnimalGalleryItem::find()
|
||||
->where(['animal_id' => (int)$animal->id, 'file_path' => $storedPath])
|
||||
->exists();
|
||||
|
||||
if ($exactExists || ($storedHash !== null && isset($existingHashes[$storedHash]))) {
|
||||
$absolute = Yii::getAlias('@webroot') . $storedPath;
|
||||
if (is_file($absolute)) {
|
||||
@unlink($absolute);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$item = new AnimalGalleryItem();
|
||||
$item->animal_id = (int)$animal->id;
|
||||
$item->file_path = $storedPath;
|
||||
$item->source_type = 'upload';
|
||||
$item->created_by = Yii::$app->user->isGuest ? null : (int)Yii::$app->user->id;
|
||||
if ($item->save()) {
|
||||
$added++;
|
||||
if ($storedHash !== null) {
|
||||
$existingHashes[$storedHash] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($added > 0) {
|
||||
if ($result['added'] > 0) {
|
||||
if ($this->contentContainer instanceof Space) {
|
||||
GalleryIntegrationService::ensureAnimalGallery($animal, $this->contentContainer);
|
||||
}
|
||||
$this->view->success(Yii::t('AnimalManagementModule.base', '{count} image(s) added to gallery.', ['count' => $added]));
|
||||
$this->view->success(Yii::t('AnimalManagementModule.base', '{count} image(s) added to gallery.', ['count' => $result['added']]));
|
||||
} else {
|
||||
$this->view->error(Yii::t('AnimalManagementModule.base', 'No gallery images were added. Check image type/size requirements.'));
|
||||
}
|
||||
@@ -576,6 +593,63 @@ class AnimalsController extends ContentContainerController
|
||||
return $this->redirect($this->contentContainer->createUrl('/animal_management/animals/view', ['id' => $animal->id]) . '#animal-gallery');
|
||||
}
|
||||
|
||||
public function actionAddGalleryImagesInline(int $id)
|
||||
{
|
||||
$animal = $this->findAnimal($id);
|
||||
$returnTo = (string)Yii::$app->request->post('returnTo', Yii::$app->request->get('returnTo', 'view'));
|
||||
$isInline = (int)Yii::$app->request->get('inline', 1) === 1;
|
||||
$maxUploadCount = 10;
|
||||
$errorMessage = '';
|
||||
$infoMessage = '';
|
||||
|
||||
if (Yii::$app->request->isPost) {
|
||||
$result = $this->processGalleryUploads($animal);
|
||||
|
||||
if (!$result['hadSelection']) {
|
||||
$errorMessage = Yii::t('AnimalManagementModule.base', 'No gallery images were selected.');
|
||||
} else {
|
||||
if ($result['wasLimited']) {
|
||||
$infoMessage = Yii::t('AnimalManagementModule.base', 'Only the first {count} selected images were processed.', ['count' => $result['maxUploadCount']]);
|
||||
}
|
||||
|
||||
if ($result['added'] > 0) {
|
||||
if ($this->contentContainer instanceof Space) {
|
||||
GalleryIntegrationService::ensureAnimalGallery($animal, $this->contentContainer);
|
||||
}
|
||||
$this->view->success(Yii::t('AnimalManagementModule.base', '{count} image(s) added to gallery.', ['count' => $result['added']]));
|
||||
if ($isInline) {
|
||||
return $this->renderAjax('inline-edit-result', [
|
||||
'collapseId' => 'gallery-add-inline',
|
||||
'refreshSelectors' => ['#animal-gallery-panel'],
|
||||
]);
|
||||
}
|
||||
return $this->redirectToAnimalPage((int)$animal->id, $returnTo);
|
||||
}
|
||||
|
||||
$errorMessage = Yii::t('AnimalManagementModule.base', 'No gallery images were added. Check image type/size requirements.');
|
||||
}
|
||||
}
|
||||
|
||||
$galleryItems = $animal->getGalleryItems()->orderBy(['id' => SORT_DESC])->limit(120)->all();
|
||||
|
||||
$params = [
|
||||
'space' => $this->contentContainer,
|
||||
'animal' => $animal,
|
||||
'galleryItems' => $galleryItems,
|
||||
'isInline' => $isInline,
|
||||
'returnTo' => $returnTo,
|
||||
'maxUploadCount' => $maxUploadCount,
|
||||
'errorMessage' => $errorMessage,
|
||||
'infoMessage' => $infoMessage,
|
||||
];
|
||||
|
||||
if ($isInline) {
|
||||
return $this->renderAjax('add-gallery-images-inline', $params);
|
||||
}
|
||||
|
||||
return $this->render('add-gallery-images-inline', $params);
|
||||
}
|
||||
|
||||
public function actionRemoveGalleryImage(int $id, int $galleryId)
|
||||
{
|
||||
$animal = $this->findAnimal($id);
|
||||
@@ -646,6 +720,9 @@ class AnimalsController extends ContentContainerController
|
||||
$animal = $this->findAnimal($id);
|
||||
$this->ensureMedicalMediaFieldDefinition();
|
||||
$form = new AnimalMedicalVisitForm(['animal' => $animal]);
|
||||
if (trim((string)$form->visit_at) === '') {
|
||||
$form->visit_at = date('Y-m-d\TH:i');
|
||||
}
|
||||
$returnTo = (string)Yii::$app->request->post('returnTo', Yii::$app->request->get('returnTo', 'medical-visits'));
|
||||
$isInline = (int)Yii::$app->request->get('inline', 1) === 1;
|
||||
|
||||
@@ -1258,6 +1335,105 @@ class AnimalsController extends ContentContainerController
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function processGalleryUploads(Animal $animal): array
|
||||
{
|
||||
$uploadedFiles = UploadedFile::getInstancesByName('galleryImages');
|
||||
$maxUploadCount = 10;
|
||||
$hadSelection = !empty($uploadedFiles);
|
||||
$wasLimited = false;
|
||||
|
||||
if (!$hadSelection) {
|
||||
return [
|
||||
'hadSelection' => false,
|
||||
'wasLimited' => false,
|
||||
'maxUploadCount' => $maxUploadCount,
|
||||
'added' => 0,
|
||||
];
|
||||
}
|
||||
|
||||
if (count($uploadedFiles) > $maxUploadCount) {
|
||||
$uploadedFiles = array_slice($uploadedFiles, 0, $maxUploadCount);
|
||||
$wasLimited = true;
|
||||
}
|
||||
|
||||
$allowedExtensions = array_map('strtolower', UploadStandards::imageExtensions());
|
||||
$allowedMimeTypes = array_map('strtolower', UploadStandards::imageMimeTypes());
|
||||
$maxBytes = (int)UploadStandards::IMAGE_MAX_BYTES;
|
||||
$existingItems = AnimalGalleryItem::find()->where(['animal_id' => (int)$animal->id])->all();
|
||||
$existingHashes = [];
|
||||
foreach ($existingItems as $existingItem) {
|
||||
$existingUrl = trim((string)$existingItem->getImageUrl());
|
||||
if ($existingUrl === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$hash = $this->computeImageContentHash($existingUrl);
|
||||
if ($hash !== null) {
|
||||
$existingHashes[$hash] = true;
|
||||
}
|
||||
}
|
||||
|
||||
$added = 0;
|
||||
foreach ($uploadedFiles as $uploadedFile) {
|
||||
if (!$uploadedFile instanceof UploadedFile) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$extension = strtolower((string)$uploadedFile->extension);
|
||||
$mimeType = strtolower((string)$uploadedFile->type);
|
||||
|
||||
if (!in_array($extension, $allowedExtensions, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($mimeType !== '' && !in_array($mimeType, $allowedMimeTypes, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($uploadedFile->size > $maxBytes) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$storedPath = $this->storeGalleryUpload($animal, $uploadedFile);
|
||||
if ($storedPath === null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$storedHash = $this->computeImageContentHash($storedPath);
|
||||
|
||||
$exactExists = AnimalGalleryItem::find()
|
||||
->where(['animal_id' => (int)$animal->id, 'file_path' => $storedPath])
|
||||
->exists();
|
||||
|
||||
if ($exactExists || ($storedHash !== null && isset($existingHashes[$storedHash]))) {
|
||||
$absolute = Yii::getAlias('@webroot') . $storedPath;
|
||||
if (is_file($absolute)) {
|
||||
@unlink($absolute);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$item = new AnimalGalleryItem();
|
||||
$item->animal_id = (int)$animal->id;
|
||||
$item->file_path = $storedPath;
|
||||
$item->source_type = 'upload';
|
||||
$item->created_by = Yii::$app->user->isGuest ? null : (int)Yii::$app->user->id;
|
||||
if ($item->save()) {
|
||||
$added++;
|
||||
if ($storedHash !== null) {
|
||||
$existingHashes[$storedHash] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [
|
||||
'hadSelection' => true,
|
||||
'wasLimited' => $wasLimited,
|
||||
'maxUploadCount' => $maxUploadCount,
|
||||
'added' => $added,
|
||||
];
|
||||
}
|
||||
|
||||
private function storeGalleryUpload(Animal $animal, UploadedFile $file): ?string
|
||||
{
|
||||
$random = Yii::$app->security->generateRandomString(8);
|
||||
@@ -1707,4 +1883,74 @@ class AnimalsController extends ContentContainerController
|
||||
$item->created_by = Yii::$app->user->isGuest ? null : (int)Yii::$app->user->id;
|
||||
$item->save();
|
||||
}
|
||||
|
||||
private function canUseIntakeGoalSection(): bool
|
||||
{
|
||||
if (!($this->contentContainer instanceof Space)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$this->contentContainer->moduleManager->isEnabled('donations')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$goalFormClass = 'humhub\\modules\\donations\\models\\forms\\DonationGoalForm';
|
||||
$goalClass = 'humhub\\modules\\donations\\models\\DonationGoal';
|
||||
|
||||
if (!class_exists($goalFormClass) || !class_exists($goalClass)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Yii::$app->db->schema->getTableSchema($goalClass::tableName(), true) !== null;
|
||||
}
|
||||
|
||||
private function createIntakeAnimalGoal(Animal $animal, array $payload): ?string
|
||||
{
|
||||
if ((int)($payload['enabled'] ?? 0) !== 1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!$this->canUseIntakeGoalSection()) {
|
||||
return Yii::t('AnimalManagementModule.base', 'Animal was created, but donation goal setup is not available in this space.');
|
||||
}
|
||||
|
||||
$goalFormClass = 'humhub\\modules\\donations\\models\\forms\\DonationGoalForm';
|
||||
$goalClass = 'humhub\\modules\\donations\\models\\DonationGoal';
|
||||
|
||||
$targetAmount = max(0.0, (float)($payload['target_amount'] ?? 0));
|
||||
if ($targetAmount <= 0) {
|
||||
return Yii::t('AnimalManagementModule.base', 'Animal was created, but the intake donation goal target must be greater than zero.');
|
||||
}
|
||||
|
||||
$title = trim((string)($payload['title'] ?? ''));
|
||||
if ($title === '') {
|
||||
$title = Yii::t('AnimalManagementModule.base', '{animalName} Care Fund', ['animalName' => $animal->getDisplayName()]);
|
||||
}
|
||||
|
||||
$description = trim((string)($payload['description'] ?? ''));
|
||||
$imagePath = trim((string)($payload['image_path'] ?? ''));
|
||||
$isActive = (int)($payload['is_active'] ?? 1) === 1;
|
||||
|
||||
$goalForm = new $goalFormClass();
|
||||
$goalForm->contentContainer = $this->contentContainer;
|
||||
$goalForm->goal_type = $goalClass::TYPE_ANIMAL;
|
||||
$goalForm->target_animal_id = (int)$animal->id;
|
||||
$goalForm->title = $title;
|
||||
$goalForm->description = $description;
|
||||
$goalForm->target_amount = $targetAmount;
|
||||
$goalForm->is_active = $isActive;
|
||||
|
||||
if ($imagePath !== '') {
|
||||
$goalForm->imageGalleryPath = $imagePath;
|
||||
}
|
||||
|
||||
$savedGoal = $goalForm->save();
|
||||
if ($savedGoal === null) {
|
||||
$firstErrors = $goalForm->getFirstErrors();
|
||||
$errorText = !empty($firstErrors) ? implode(' ', array_values($firstErrors)) : Yii::t('AnimalManagementModule.base', 'Unknown donation goal error.');
|
||||
return Yii::t('AnimalManagementModule.base', 'Animal was created, but donation goal could not be saved: {error}', ['error' => $errorText]);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,11 +5,13 @@ namespace humhub\modules\animal_management\controllers;
|
||||
use humhub\modules\animal_management\models\Animal;
|
||||
use humhub\modules\animal_management\models\forms\DisplaySettingsForm;
|
||||
use humhub\modules\animal_management\models\forms\FieldDefinitionSettingsForm;
|
||||
use humhub\modules\animal_management\services\ModuleSetupService;
|
||||
use humhub\modules\content\components\ContentContainerController;
|
||||
use humhub\modules\content\components\ContentContainerControllerAccess;
|
||||
use humhub\modules\rescue_foundation\widgets\RescueSettingsMenu;
|
||||
use humhub\modules\space\models\Space;
|
||||
use Yii;
|
||||
use yii\web\BadRequestHttpException;
|
||||
|
||||
class SettingsController extends ContentContainerController
|
||||
{
|
||||
@@ -53,6 +55,37 @@ class SettingsController extends ContentContainerController
|
||||
'animalCount' => (int)$animalCount,
|
||||
'fieldSettingsForm' => $fieldSettingsForm,
|
||||
'displaySettingsForm' => $displaySettingsForm,
|
||||
'space' => $this->contentContainer,
|
||||
]);
|
||||
}
|
||||
|
||||
public function actionSetup()
|
||||
{
|
||||
if (!Yii::$app->request->isPost) {
|
||||
throw new BadRequestHttpException('Invalid request method.');
|
||||
}
|
||||
|
||||
if (!$this->contentContainer instanceof Space) {
|
||||
$this->view->error(Yii::t('AnimalManagementModule.base', 'Setup can only be run inside a space.'));
|
||||
return $this->redirect($this->contentContainer->createUrl('/animal_management/settings'));
|
||||
}
|
||||
|
||||
try {
|
||||
$result = ModuleSetupService::runForSpace($this->contentContainer);
|
||||
$appliedCount = count($result['applied'] ?? []);
|
||||
|
||||
if ($appliedCount > 0) {
|
||||
$this->view->success(Yii::t('AnimalManagementModule.base', 'Setup completed. Applied {count} migration(s).', [
|
||||
'count' => $appliedCount,
|
||||
]));
|
||||
} else {
|
||||
$this->view->success(Yii::t('AnimalManagementModule.base', 'Setup completed. No pending migrations were found.'));
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
Yii::error($e, 'animal_management.setup');
|
||||
$this->view->error(Yii::t('AnimalManagementModule.base', 'Setup failed. Please check logs and try again.'));
|
||||
}
|
||||
|
||||
return $this->redirect($this->contentContainer->createUrl('/animal_management/settings'));
|
||||
}
|
||||
}
|
||||
|
||||
41
events/AnimalTileRenderEvent.php
Normal file
41
events/AnimalTileRenderEvent.php
Normal file
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace humhub\modules\animal_management\events;
|
||||
|
||||
use humhub\modules\animal_management\models\Animal;
|
||||
use humhub\modules\content\components\ContentContainerActiveRecord;
|
||||
use yii\base\Event;
|
||||
|
||||
class AnimalTileRenderEvent extends Event
|
||||
{
|
||||
public const EVENT_RENDER_OVERLAY = 'renderOverlay';
|
||||
|
||||
public Animal $animal;
|
||||
public ContentContainerActiveRecord $contentContainer;
|
||||
public $existingDonationGoal = null;
|
||||
public bool $showDonationSettingsButton = false;
|
||||
public string $donationToggleInputId = '';
|
||||
public string $donationInlineFormId = '';
|
||||
|
||||
/** @var string[] */
|
||||
private array $htmlFragments = [];
|
||||
|
||||
public function addHtml(string $html): void
|
||||
{
|
||||
$html = trim($html);
|
||||
if ($html === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->htmlFragments[] = $html;
|
||||
}
|
||||
|
||||
public function getHtml(): string
|
||||
{
|
||||
if (empty($this->htmlFragments)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return implode("\n", $this->htmlFragments);
|
||||
}
|
||||
}
|
||||
32
events/AnimalTileSizeEvent.php
Normal file
32
events/AnimalTileSizeEvent.php
Normal file
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace humhub\modules\animal_management\events;
|
||||
|
||||
use humhub\modules\animal_management\models\Animal;
|
||||
use humhub\modules\content\components\ContentContainerActiveRecord;
|
||||
use yii\base\Event;
|
||||
|
||||
class AnimalTileSizeEvent extends Event
|
||||
{
|
||||
public const EVENT_RESOLVE_SIZE = 'resolveSize';
|
||||
|
||||
public Animal $animal;
|
||||
public ContentContainerActiveRecord $contentContainer;
|
||||
public $existingDonationGoal = null;
|
||||
|
||||
private int $additionalHeightPx = 0;
|
||||
|
||||
public function addAdditionalHeightPx(int $heightPx): void
|
||||
{
|
||||
if ($heightPx <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->additionalHeightPx += $heightPx;
|
||||
}
|
||||
|
||||
public function getAdditionalHeightPx(): int
|
||||
{
|
||||
return max(0, $this->additionalHeightPx);
|
||||
}
|
||||
}
|
||||
@@ -61,6 +61,8 @@ class AnimalStreamPublisherService
|
||||
$entry->medical_visit_id = $medicalVisitId;
|
||||
$entry->progress_update_id = $progressUpdateId;
|
||||
$entry->content->container = $space;
|
||||
// Respect each space's configured stream visibility policy.
|
||||
$entry->content->visibility = (int)$space->getDefaultContentVisibility();
|
||||
|
||||
if (!$entry->save()) {
|
||||
Yii::warning([
|
||||
|
||||
72
services/ModuleSetupService.php
Normal file
72
services/ModuleSetupService.php
Normal file
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
namespace humhub\modules\animal_management\services;
|
||||
|
||||
use humhub\modules\space\models\Space;
|
||||
use Yii;
|
||||
|
||||
class ModuleSetupService
|
||||
{
|
||||
public static function runForSpace(Space $space): array
|
||||
{
|
||||
$result = static::applyModuleMigrations();
|
||||
|
||||
$settings = Yii::$app->getModule('animal_management')->settings->contentContainer($space);
|
||||
if ($settings->get('searchBlockHeading') === null) {
|
||||
$settings->set('searchBlockHeading', 'Animals Available for Intake & Transfer');
|
||||
$result['defaultsApplied'] = ['searchBlockHeading'];
|
||||
} else {
|
||||
$result['defaultsApplied'] = [];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private static function applyModuleMigrations(): array
|
||||
{
|
||||
$migrationDir = dirname(__DIR__) . '/migrations';
|
||||
$files = glob($migrationDir . '/m*.php') ?: [];
|
||||
sort($files, SORT_NATURAL);
|
||||
|
||||
$existingVersions = Yii::$app->db->createCommand('SELECT version FROM migration')->queryColumn();
|
||||
$history = array_fill_keys($existingVersions, true);
|
||||
|
||||
$applied = [];
|
||||
$skipped = [];
|
||||
|
||||
foreach ($files as $file) {
|
||||
$version = pathinfo($file, PATHINFO_FILENAME);
|
||||
if (isset($history[$version])) {
|
||||
$skipped[] = $version;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!class_exists($version, false)) {
|
||||
require_once $file;
|
||||
}
|
||||
|
||||
if (!class_exists($version, false)) {
|
||||
throw new \RuntimeException('Migration class not found: ' . $version);
|
||||
}
|
||||
|
||||
$migration = new $version();
|
||||
$ok = method_exists($migration, 'safeUp') ? $migration->safeUp() : $migration->up();
|
||||
if ($ok === false) {
|
||||
throw new \RuntimeException('Migration failed: ' . $version);
|
||||
}
|
||||
|
||||
Yii::$app->db->createCommand()->insert('migration', [
|
||||
'version' => $version,
|
||||
'apply_time' => time(),
|
||||
])->execute();
|
||||
|
||||
$applied[] = $version;
|
||||
$history[$version] = true;
|
||||
}
|
||||
|
||||
return [
|
||||
'applied' => $applied,
|
||||
'skipped' => $skipped,
|
||||
];
|
||||
}
|
||||
}
|
||||
184
views/animals/_tablet_quick_donate_extras.php
Normal file
184
views/animals/_tablet_quick_donate_extras.php
Normal file
@@ -0,0 +1,184 @@
|
||||
<?php
|
||||
|
||||
use humhub\libs\Html;
|
||||
|
||||
/*
|
||||
* @var array $donationHistoryRows
|
||||
* @var bool $showDonationSettingsButton
|
||||
* @var string $goalEditorToggleId
|
||||
* @var int $existingGoalId
|
||||
* @var string $createInlineGoalUrl
|
||||
* @var string $existingGoalTitle
|
||||
* @var float $existingGoalTargetAmount
|
||||
* @var string $existingGoalDescription
|
||||
* @var string $existingGoalImage
|
||||
* @var array $galleryUrls
|
||||
* @var \humhub\modules\animal_management\models\Animal $animal
|
||||
* @var int $existingGoalActive
|
||||
* @var string $fileFieldId
|
||||
* @var string $previewId
|
||||
* @var string $quickDonateToggleId
|
||||
* @var string $quickDonatePanelId
|
||||
*/
|
||||
?>
|
||||
<div class="animal-tile-quick-donate-layout<?= $showDonationSettingsButton ? ' has-goal-settings' : '' ?>">
|
||||
<div class="animal-tile-quick-donate-history-col">
|
||||
<div style="font-size:14px;font-weight:700;color:#f8fafc;margin-bottom:6px;"><?= Yii::t('DonationsModule.base', 'Donation History') ?></div>
|
||||
<?php if (empty($donationHistoryRows)): ?>
|
||||
<div style="font-size:12px;color:rgba(226,232,240,0.9);"><?= Yii::t('DonationsModule.base', 'No donations yet.') ?></div>
|
||||
<?php else: ?>
|
||||
<div class="animal-tile-scroll-region" style="flex:1 1 auto;min-height:0;overflow-y:auto;">
|
||||
<?php foreach ($donationHistoryRows as $donationRow): ?>
|
||||
<div class="animal-tile-donation-history-item">
|
||||
<div class="animal-tile-donation-history-meta">
|
||||
<?php if (!empty($donationRow['avatarUrl'])): ?>
|
||||
<img class="animal-tile-donation-history-avatar" src="<?= Html::encode((string)$donationRow['avatarUrl']) ?>" alt="<?= Html::encode((string)$donationRow['donor']) ?>">
|
||||
<?php else: ?>
|
||||
<span class="animal-tile-donation-history-avatar animal-tile-donation-history-avatar-fallback">
|
||||
<i class="fa fa-user"></i>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
<div class="animal-tile-donation-history-identity">
|
||||
<?php if (!empty($donationRow['donorUrl'])): ?>
|
||||
<?= Html::a(
|
||||
Html::encode($donationRow['donor']),
|
||||
(string)$donationRow['donorUrl'],
|
||||
['class' => 'animal-tile-donation-history-name']
|
||||
) ?>
|
||||
<?php else: ?>
|
||||
<span class="animal-tile-donation-history-name"><?= Html::encode($donationRow['donor']) ?></span>
|
||||
<?php endif; ?>
|
||||
<span class="animal-tile-donation-history-when"><?= Html::encode((string)($donationRow['when'] ?? '')) ?></span>
|
||||
</div>
|
||||
</div>
|
||||
<span class="animal-tile-donation-history-amount"><?= Html::encode($donationRow['amount']) ?></span>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
__ANIMAL_TILE_QUICK_DONATE_FORM_SLOT__
|
||||
|
||||
<?php if ($showDonationSettingsButton): ?>
|
||||
<div class="animal-tile-quick-donate-goal-col">
|
||||
<input type="checkbox" id="<?= Html::encode($goalEditorToggleId) ?>" class="animal-tile-goal-editor-toggle" <?= $existingGoalId > 0 ? 'checked' : '' ?>>
|
||||
<?php if ($existingGoalId <= 0): ?>
|
||||
<label for="<?= Html::encode($goalEditorToggleId) ?>" class="btn btn-default btn-xs animal-tile-set-goal-btn" style="margin:0 0 8px 0;align-self:flex-start;">
|
||||
<i class="fa fa-plus"></i> <?= Yii::t('DonationsModule.base', 'Set Goal') ?>
|
||||
</label>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="animal-tile-goal-editor-fields animal-tile-scroll-region" style="<?= $existingGoalId > 0 ? 'display:flex;flex-direction:column;flex:1 1 auto;min-height:0;overflow-y:auto;' : 'display:none;flex-direction:column;flex:1 1 auto;min-height:0;overflow-y:auto;' ?>">
|
||||
<?= Html::beginForm($createInlineGoalUrl, 'post', [
|
||||
'enctype' => 'multipart/form-data',
|
||||
'style' => 'margin:0;',
|
||||
]) ?>
|
||||
<?= Html::hiddenInput(Yii::$app->request->csrfParam, Yii::$app->request->getCsrfToken()) ?>
|
||||
<?= Html::hiddenInput('DonationGoalForm[id]', $existingGoalId) ?>
|
||||
<?= Html::hiddenInput('DonationGoalForm[goal_type]', 'animal') ?>
|
||||
<?= Html::hiddenInput('DonationGoalForm[target_animal_id]', (int)$animal->id) ?>
|
||||
<?= Html::hiddenInput('DonationGoalForm[is_active]', $existingGoalActive) ?>
|
||||
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px;">
|
||||
<div style="font-size:14px;font-weight:700;color:#f8fafc;"><?= Yii::t('DonationsModule.base', 'Goal Settings') ?></div>
|
||||
<div style="display:flex;align-items:center;gap:8px;">
|
||||
<button type="submit" class="animal-tile-goal-header-action" title="<?= Yii::t('DonationsModule.base', 'Save Goal') ?>" aria-label="<?= Yii::t('DonationsModule.base', 'Save Goal') ?>">
|
||||
<i class="fa fa-check"></i>
|
||||
</button>
|
||||
<label for="<?= Html::encode($quickDonateToggleId) ?>" class="animal-tile-goal-header-action" title="<?= Yii::t('AnimalManagementModule.base', 'Close') ?>" aria-label="<?= Yii::t('AnimalManagementModule.base', 'Close') ?>">
|
||||
<i class="fa fa-times"></i>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="animal-tile-goal-title-target-row" style="display:grid;grid-template-columns:minmax(0,1fr) minmax(0,180px);gap:10px;align-items:end;margin-bottom:8px;">
|
||||
<div class="form-group" style="margin-bottom:0;min-width:0;">
|
||||
<label style="font-size:12px;font-weight:600;margin-bottom:4px;display:block;"><?= Yii::t('DonationsModule.base', 'Title') ?></label>
|
||||
<?= Html::textInput('DonationGoalForm[title]', $existingGoalTitle, [
|
||||
'class' => 'form-control input-sm',
|
||||
'maxlength' => 190,
|
||||
'required' => true,
|
||||
]) ?>
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom:0;min-width:0;">
|
||||
<label style="font-size:12px;font-weight:600;margin-bottom:4px;display:block;"><?= Yii::t('DonationsModule.base', 'Target') ?></label>
|
||||
<div class="input-group" style="width:100%;max-width:none;">
|
||||
<span class="input-group-addon" style="background:rgba(255,255,255,0.12);border-color:rgba(255,255,255,0.24);color:#f8fafc;">$</span>
|
||||
<?= Html::input('number', 'DonationGoalForm[target_amount]', $existingGoalTargetAmount > 0 ? (string)round($existingGoalTargetAmount) : '', [
|
||||
'class' => 'form-control input-sm',
|
||||
'step' => '1',
|
||||
'min' => '1',
|
||||
'inputmode' => 'numeric',
|
||||
'required' => true,
|
||||
]) ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom:8px;">
|
||||
<label style="font-size:12px;font-weight:600;margin-bottom:4px;display:block;"><?= Yii::t('DonationsModule.base', 'Description') ?></label>
|
||||
<?= Html::textarea('DonationGoalForm[description]', $existingGoalDescription, [
|
||||
'class' => 'form-control input-sm',
|
||||
'rows' => 2,
|
||||
]) ?>
|
||||
</div>
|
||||
|
||||
<div class="form-group" style="margin-bottom:8px;">
|
||||
<label style="font-size:12px;font-weight:600;margin-bottom:4px;display:block;"><?= Yii::t('DonationsModule.base', 'Image') ?></label>
|
||||
<div class="animal-tile-goal-image-row" style="display:flex;align-items:flex-start;gap:10px;margin-bottom:8px;">
|
||||
<div id="<?= Html::encode($previewId) ?>" class="animal-tile-goal-selected-image text-muted" style="font-size:12px;">
|
||||
<?php if ($existingGoalImage !== ''): ?>
|
||||
<img class="animal-tile-goal-selected-image-thumb" src="<?= Html::encode($existingGoalImage) ?>" alt="">
|
||||
<?php else: ?>
|
||||
<span class="animal-tile-goal-selected-image-empty"><?= Yii::t('DonationsModule.base', 'No image selected.') ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="animal-tile-goal-image-list" style="display:flex;flex-wrap:wrap;gap:6px;min-width:0;flex:1 1 auto;align-content:flex-start;">
|
||||
<?php if (!empty($galleryUrls)): ?>
|
||||
<?php foreach ($galleryUrls as $galleryIndex => $galleryUrl): ?>
|
||||
<?php $galleryOptionId = 'animal-donation-gallery-option-' . (int)$animal->id . '-' . (int)$galleryIndex; ?>
|
||||
<div style="position:relative;">
|
||||
<input
|
||||
type="radio"
|
||||
class="animal-donation-gallery-radio"
|
||||
id="<?= Html::encode($galleryOptionId) ?>"
|
||||
name="DonationGoalForm[imageGalleryPath]"
|
||||
value="<?= Html::encode($galleryUrl) ?>"
|
||||
data-preview="#<?= Html::encode($previewId) ?>"
|
||||
data-editor-bg="#<?= Html::encode($quickDonatePanelId) ?>"
|
||||
<?= $existingGoalImage === $galleryUrl ? 'checked' : '' ?>
|
||||
>
|
||||
<label
|
||||
for="<?= Html::encode($galleryOptionId) ?>"
|
||||
class="animal-donation-inline-gallery-item"
|
||||
style="display:block;border:1px solid rgba(255,255,255,0.2);background:rgba(15,23,42,0.22);padding:3px;border-radius:4px;line-height:0;pointer-events:auto;cursor:pointer;"
|
||||
>
|
||||
<img src="<?= Html::encode($galleryUrl) ?>" alt="" style="width:56px;height:56px;object-fit:cover;border-radius:2px;">
|
||||
</label>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php else: ?>
|
||||
<div class="text-muted" style="font-size:12px;align-self:center;"><?= Yii::t('DonationsModule.base', 'No gallery images found for this animal.') ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?= Html::fileInput('DonationGoalForm[imageFile]', null, [
|
||||
'id' => $fileFieldId,
|
||||
'class' => 'js-animal-donation-upload animal-tile-goal-upload-input',
|
||||
'data-preview' => '#' . $previewId,
|
||||
'data-editor-bg' => '#' . $quickDonatePanelId,
|
||||
'accept' => 'image/*',
|
||||
]) ?>
|
||||
<label for="<?= Html::encode($fileFieldId) ?>" class="animal-tile-goal-upload-btn">
|
||||
<?= Yii::t('DonationsModule.base', 'Upload') ?>
|
||||
</label>
|
||||
</div>
|
||||
<?= Html::endForm() ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -33,6 +33,30 @@ switch ($transfer->status) {
|
||||
$statusTextColor = '#d1d5db';
|
||||
break;
|
||||
}
|
||||
|
||||
static $transferActionButtonStylePrinted = false;
|
||||
if (!$transferActionButtonStylePrinted):
|
||||
$transferActionButtonStylePrinted = true;
|
||||
?>
|
||||
<style>
|
||||
.animal-transfer-action-btn {
|
||||
border-radius: 999px;
|
||||
border: 1px solid rgba(15, 23, 42, 0.24);
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
color: #0f172a !important;
|
||||
font-weight: 700;
|
||||
box-shadow: 0 2px 10px rgba(15, 23, 42, 0.2);
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.animal-transfer-action-btn {
|
||||
border-color: rgba(226, 232, 240, 0.34);
|
||||
background: rgba(15, 23, 42, 0.72);
|
||||
color: #f8fafc !important;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<?php endif; ?>
|
||||
?>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:0;overflow:hidden;border-radius:12px;border:0;box-shadow:0 8px 24px rgba(15,23,42,0.14);">
|
||||
@@ -69,18 +93,16 @@ switch ($transfer->status) {
|
||||
Yii::t('AnimalManagementModule.base', 'Accept'),
|
||||
$space->createUrl('/animal_management/animals/transfer-respond', ['id' => $transfer->id, 'decision' => 'accept']),
|
||||
[
|
||||
'class' => 'btn btn-xs btn-default',
|
||||
'class' => 'btn btn-xs btn-default animal-transfer-action-btn',
|
||||
'data-method' => 'post',
|
||||
'style' => 'border-radius:999px;border:0;background:rgba(255,255,255,0.92);font-weight:600;'
|
||||
]
|
||||
) ?>
|
||||
<?= Html::a(
|
||||
Yii::t('AnimalManagementModule.base', 'Decline'),
|
||||
$space->createUrl('/animal_management/animals/transfer-respond', ['id' => $transfer->id, 'decision' => 'decline']),
|
||||
[
|
||||
'class' => 'btn btn-xs btn-default',
|
||||
'class' => 'btn btn-xs btn-default animal-transfer-action-btn',
|
||||
'data-method' => 'post',
|
||||
'style' => 'border-radius:999px;border:0;background:rgba(255,255,255,0.92);font-weight:600;'
|
||||
]
|
||||
) ?>
|
||||
<?php elseif ($isIncoming && $transfer->status === AnimalTransfer::STATUS_ACCEPTED): ?>
|
||||
@@ -88,9 +110,8 @@ switch ($transfer->status) {
|
||||
Yii::t('AnimalManagementModule.base', 'Complete Transfer'),
|
||||
$space->createUrl('/animal_management/animals/transfer-complete', ['id' => $transfer->id]),
|
||||
[
|
||||
'class' => 'btn btn-xs btn-default',
|
||||
'class' => 'btn btn-xs btn-default animal-transfer-action-btn',
|
||||
'data-method' => 'post',
|
||||
'style' => 'border-radius:999px;border:0;background:rgba(255,255,255,0.92);font-weight:600;'
|
||||
]
|
||||
) ?>
|
||||
<?php elseif (!$isIncoming && in_array($transfer->status, [AnimalTransfer::STATUS_REQUESTED, AnimalTransfer::STATUS_ACCEPTED], true)): ?>
|
||||
@@ -98,9 +119,8 @@ switch ($transfer->status) {
|
||||
Yii::t('AnimalManagementModule.base', 'Cancel Request'),
|
||||
$space->createUrl('/animal_management/animals/transfer-cancel', ['id' => $transfer->id]),
|
||||
[
|
||||
'class' => 'btn btn-xs btn-default',
|
||||
'class' => 'btn btn-xs btn-default animal-transfer-action-btn',
|
||||
'data-method' => 'post',
|
||||
'style' => 'border-radius:999px;border:0;background:rgba(255,255,255,0.92);font-weight:600;'
|
||||
]
|
||||
) ?>
|
||||
<?php endif; ?>
|
||||
|
||||
305
views/animals/add-gallery-images-inline.php
Normal file
305
views/animals/add-gallery-images-inline.php
Normal file
@@ -0,0 +1,305 @@
|
||||
<?php
|
||||
|
||||
use humhub\modules\animal_management\models\Animal;
|
||||
use humhub\modules\animal_management\models\AnimalGalleryItem;
|
||||
use humhub\modules\space\models\Space;
|
||||
use yii\helpers\Html;
|
||||
use yii\helpers\Json;
|
||||
|
||||
/* @var Space $space */
|
||||
/* @var Animal $animal */
|
||||
/* @var AnimalGalleryItem[] $galleryItems */
|
||||
/* @var bool $isInline */
|
||||
/* @var string $returnTo */
|
||||
/* @var int $maxUploadCount */
|
||||
/* @var string $errorMessage */
|
||||
/* @var string $infoMessage */
|
||||
|
||||
$isInline = isset($isInline) ? (bool)$isInline : false;
|
||||
$showTopCancel = (string)Yii::$app->request->get('showTopCancel', '0') === '1';
|
||||
$returnTo = (string)($returnTo ?? 'view');
|
||||
$maxUploadCount = max(1, (int)($maxUploadCount ?? 10));
|
||||
$errorMessage = trim((string)($errorMessage ?? ''));
|
||||
$infoMessage = trim((string)($infoMessage ?? ''));
|
||||
$formId = 'animal-gallery-inline-upload-form';
|
||||
$submitUrl = $space->createUrl('/animal_management/animals/add-gallery-images-inline', [
|
||||
'id' => (int)$animal->id,
|
||||
'inline' => $isInline ? 1 : 0,
|
||||
'returnTo' => $returnTo,
|
||||
]);
|
||||
|
||||
$this->registerCss(<<<CSS
|
||||
.inline-add-shell.panel {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(255, 255, 255, 0.22);
|
||||
border-radius: 12px;
|
||||
background: rgba(10, 18, 28, 0.36);
|
||||
}
|
||||
|
||||
.inline-add-shell > .panel-body {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
background: rgba(10, 18, 28, 0.2);
|
||||
}
|
||||
|
||||
.inline-add-shell,
|
||||
.inline-add-shell .panel-body,
|
||||
.inline-add-shell .control-label,
|
||||
.inline-add-shell .help-block,
|
||||
.inline-add-shell h4 {
|
||||
color: #eef5fb;
|
||||
}
|
||||
|
||||
.inline-add-shell .form-control {
|
||||
background: rgba(10, 18, 28, 0.56);
|
||||
border-color: rgba(255, 255, 255, 0.44);
|
||||
color: #f3f8ff;
|
||||
}
|
||||
|
||||
.inline-add-shell .animal-inline-top-save-action {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
padding: 0;
|
||||
border-radius: 999px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.36);
|
||||
background: rgba(15, 23, 42, 0.72);
|
||||
color: #f8fafc;
|
||||
cursor: pointer;
|
||||
line-height: 1;
|
||||
font-size: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28);
|
||||
}
|
||||
|
||||
.inline-add-shell .animal-inline-top-save-action:hover,
|
||||
.inline-add-shell .animal-inline-top-save-action:focus {
|
||||
background: rgba(30, 41, 59, 0.86);
|
||||
border-color: rgba(255, 255, 255, 0.5);
|
||||
color: #f8fafc;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.inline-add-shell .animal-gallery-inline-existing-grid {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.inline-add-shell .animal-gallery-inline-existing-item {
|
||||
display: block;
|
||||
width: 100%;
|
||||
aspect-ratio: 1 / 1;
|
||||
min-height: 70px;
|
||||
object-fit: cover;
|
||||
border-radius: 6px;
|
||||
}
|
||||
|
||||
.inline-add-shell .animal-gallery-inline-existing-wrap {
|
||||
min-height: 220px;
|
||||
max-height: 320px;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
margin: 6px 0 10px 0;
|
||||
padding-right: 4px;
|
||||
}
|
||||
|
||||
.inline-add-shell .animal-gallery-inline-file-input {
|
||||
position: absolute;
|
||||
left: -10000px;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.inline-add-shell .animal-gallery-inline-file-trigger {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.inline-add-shell .animal-gallery-inline-file-name {
|
||||
display: inline-block;
|
||||
margin-left: 8px;
|
||||
color: rgba(233, 242, 250, 0.9);
|
||||
font-size: 12px;
|
||||
vertical-align: middle;
|
||||
max-width: calc(100% - 150px);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
CSS
|
||||
);
|
||||
|
||||
if ($isInline) {
|
||||
$this->registerCss(<<<CSS
|
||||
html, body {
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
background: transparent !important;
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
}
|
||||
|
||||
html::-webkit-scrollbar, body::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
body > .panel:first-child {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
|
||||
body,
|
||||
.inline-add-shell,
|
||||
.inline-add-shell > .panel-body,
|
||||
#{$formId} {
|
||||
height: 100% !important;
|
||||
}
|
||||
|
||||
#{$formId} {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#{$formId} .animal-gallery-inline-existing-wrap {
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
max-height: none;
|
||||
}
|
||||
CSS
|
||||
);
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="panel panel-default inline-add-shell">
|
||||
<div class="panel-body">
|
||||
<form id="<?= Html::encode($formId) ?>" method="post" action="<?= Html::encode($submitUrl) ?>" enctype="multipart/form-data"<?= !$isInline ? ' target="_top"' : '' ?>>
|
||||
<?= Html::hiddenInput(Yii::$app->request->csrfParam, Yii::$app->request->getCsrfToken()) ?>
|
||||
<?= Html::hiddenInput('returnTo', $returnTo) ?>
|
||||
|
||||
<?php if ($isInline): ?>
|
||||
<div class="animal-inline-top-actions" style="display:flex;justify-content:flex-end;gap:8px;margin:0 38px 10px 0;">
|
||||
<?= Html::submitButton('<i class="fa fa-check"></i>', [
|
||||
'class' => 'animal-inline-top-save-action',
|
||||
'title' => Yii::t('AnimalManagementModule.base', 'Upload to Gallery'),
|
||||
'form' => $formId,
|
||||
]) ?>
|
||||
<?php if ($showTopCancel): ?>
|
||||
<?= Html::button('<i class="fa fa-times"></i>', [
|
||||
'id' => 'gallery-inline-add-cancel-icon',
|
||||
'class' => 'animal-inline-top-save-action',
|
||||
'title' => Yii::t('AnimalManagementModule.base', 'Cancel'),
|
||||
'type' => 'button',
|
||||
]) ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<h4 style="margin:0 0 10px 0;"><?= Yii::t('AnimalManagementModule.base', 'Add Images to Gallery') ?></h4>
|
||||
|
||||
<?php if ($errorMessage !== ''): ?>
|
||||
<div class="alert alert-danger" style="margin-bottom:10px;"><?= Html::encode($errorMessage) ?></div>
|
||||
<?php endif; ?>
|
||||
<?php if ($infoMessage !== ''): ?>
|
||||
<div class="alert alert-info" style="margin-bottom:10px;"><?= Html::encode($infoMessage) ?></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="form-group" style="margin-bottom:8px;">
|
||||
<label class="control-label" for="galleryImages"><?= Yii::t('AnimalManagementModule.base', 'Upload Images') ?></label>
|
||||
<div>
|
||||
<input type="file" class="animal-gallery-inline-file-input" id="galleryImages" name="galleryImages[]" accept="image/*" multiple required>
|
||||
<label for="galleryImages" class="btn btn-default btn-sm animal-gallery-inline-file-trigger"><?= Yii::t('AnimalManagementModule.base', 'Choose Files') ?></label>
|
||||
<span id="gallery-inline-file-name" class="animal-gallery-inline-file-name"><?= Yii::t('AnimalManagementModule.base', 'No files selected.') ?></span>
|
||||
</div>
|
||||
<div class="help-block" style="margin-bottom:0;"><?= Yii::t('AnimalManagementModule.base', 'You can upload up to {count} images at a time.', ['count' => $maxUploadCount]) ?></div>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($galleryItems)): ?>
|
||||
<div class="animal-gallery-inline-existing-wrap">
|
||||
<div class="row animal-gallery-inline-existing-grid">
|
||||
<?php foreach (array_slice($galleryItems, 0, 12) as $galleryItem): ?>
|
||||
<?php $galleryUrl = trim((string)$galleryItem->getImageUrl()); ?>
|
||||
<?php if ($galleryUrl === '') { continue; } ?>
|
||||
<div class="col-xs-4 col-sm-3" style="margin-bottom:8px;">
|
||||
<img src="<?= Html::encode($galleryUrl) ?>" alt="<?= Yii::t('AnimalManagementModule.base', 'Gallery image') ?>" class="animal-gallery-inline-existing-item">
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!$isInline): ?>
|
||||
<button type="submit" class="btn btn-primary"><?= Yii::t('AnimalManagementModule.base', 'Upload to Gallery') ?></button>
|
||||
<a href="<?= Html::encode($space->createUrl('/animal_management/animals/view', ['id' => $animal->id])) ?>" class="btn btn-default"><?= Yii::t('AnimalManagementModule.base', 'Cancel') ?></a>
|
||||
<?php endif; ?>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
if ($isInline) {
|
||||
$cancelPayload = Json::htmlEncode([
|
||||
'source' => 'animal-inline-editor',
|
||||
'type' => 'cancel',
|
||||
'collapseId' => 'gallery-add-inline',
|
||||
]);
|
||||
|
||||
$this->registerJs(<<<JS
|
||||
(function() {
|
||||
var fileInput = document.getElementById('galleryImages');
|
||||
var fileLabel = document.getElementById('gallery-inline-file-name');
|
||||
|
||||
function updateFileLabel() {
|
||||
if (!fileInput || !fileLabel) {
|
||||
return;
|
||||
}
|
||||
|
||||
var files = fileInput.files;
|
||||
if (!files || files.length === 0) {
|
||||
fileLabel.textContent = 'No files selected.';
|
||||
return;
|
||||
}
|
||||
|
||||
if (files.length === 1) {
|
||||
fileLabel.textContent = files[0].name || '1 file selected';
|
||||
return;
|
||||
}
|
||||
|
||||
fileLabel.textContent = files.length + ' files selected';
|
||||
}
|
||||
|
||||
if (fileInput) {
|
||||
fileInput.addEventListener('change', updateFileLabel);
|
||||
updateFileLabel();
|
||||
}
|
||||
|
||||
function postInlineCancel() {
|
||||
if (window.parent && window.parent !== window) {
|
||||
window.parent.postMessage($cancelPayload, '*');
|
||||
}
|
||||
}
|
||||
|
||||
if (window.jQuery) {
|
||||
window.jQuery(document).on('click', '#gallery-inline-add-cancel, #gallery-inline-add-cancel-icon', function() {
|
||||
postInlineCancel();
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('click', function(event) {
|
||||
var target = event.target;
|
||||
if (!target || !target.closest) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!target.closest('#gallery-inline-add-cancel, #gallery-inline-add-cancel-icon')) {
|
||||
return;
|
||||
}
|
||||
|
||||
postInlineCancel();
|
||||
}, false);
|
||||
})();
|
||||
JS
|
||||
, \yii\web\View::POS_END);
|
||||
}
|
||||
?>
|
||||
@@ -17,6 +17,7 @@ use yii\helpers\Json;
|
||||
/* @var bool $isInline */
|
||||
|
||||
$isInline = isset($isInline) ? (bool)$isInline : false;
|
||||
$showTopCancel = (string)Yii::$app->request->get('showTopCancel', '0') === '1';
|
||||
|
||||
$hiddenMedicalKeys = [
|
||||
'second_physician_name',
|
||||
@@ -135,6 +136,15 @@ $medicalMediaPath = trim((string)($model->customFields['medical_media_reference'
|
||||
$hasMedicalMedia = $medicalMediaPath !== '' && (preg_match('/^https?:\/\//i', $medicalMediaPath) || substr($medicalMediaPath, 0, 1) === '/');
|
||||
$medicalGalleryModalId = 'add-medical-media-gallery-modal';
|
||||
$medicalFormId = 'add-medical-visit-inline-form';
|
||||
$visitAtInputValue = trim((string)$model->visit_at);
|
||||
if ($visitAtInputValue === '') {
|
||||
$visitAtInputValue = date('Y-m-d\TH:i');
|
||||
} else {
|
||||
$visitAtTimestamp = strtotime($visitAtInputValue);
|
||||
if ($visitAtTimestamp !== false) {
|
||||
$visitAtInputValue = date('Y-m-d\TH:i', $visitAtTimestamp);
|
||||
}
|
||||
}
|
||||
|
||||
$this->registerCss(<<<CSS
|
||||
.inline-add-shell.panel {
|
||||
@@ -172,6 +182,18 @@ $medicalFormId = 'add-medical-visit-inline-form';
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.inline-add-shell .panel.panel-default > .panel-heading a {
|
||||
color: inherit;
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.inline-add-shell .panel.panel-default > .panel-heading a:hover,
|
||||
.inline-add-shell .panel.panel-default > .panel-heading a:focus {
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.inline-add-shell,
|
||||
.inline-add-shell .panel-body,
|
||||
.inline-add-shell .control-label,
|
||||
@@ -204,6 +226,31 @@ $medicalFormId = 'add-medical-visit-inline-form';
|
||||
.inline-add-shell select.form-control option {
|
||||
color: #0f1b2a;
|
||||
}
|
||||
|
||||
.inline-add-shell .animal-inline-top-save-action {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
padding: 0;
|
||||
border-radius: 999px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.36);
|
||||
background: rgba(15, 23, 42, 0.72);
|
||||
color: #f8fafc;
|
||||
cursor: pointer;
|
||||
line-height: 1;
|
||||
font-size: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28);
|
||||
}
|
||||
|
||||
.inline-add-shell .animal-inline-top-save-action:hover,
|
||||
.inline-add-shell .animal-inline-top-save-action:focus {
|
||||
background: rgba(30, 41, 59, 0.86);
|
||||
border-color: rgba(255, 255, 255, 0.5);
|
||||
color: #f8fafc;
|
||||
outline: none;
|
||||
}
|
||||
CSS
|
||||
);
|
||||
|
||||
@@ -213,6 +260,13 @@ html, body {
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
background: transparent !important;
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
}
|
||||
|
||||
html::-webkit-scrollbar, body::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
body > .panel:first-child {
|
||||
@@ -243,18 +297,20 @@ CSS
|
||||
<?= Html::hiddenInput('medicalMediaGalleryPath', $medicalMediaPath, ['id' => 'medical-media-gallery-path']) ?>
|
||||
|
||||
<?php if ($isInline): ?>
|
||||
<div style="display:flex;justify-content:flex-end;gap:8px;margin-bottom:10px;">
|
||||
<div class="animal-inline-top-actions" style="display:flex;justify-content:flex-end;gap:8px;margin:0 38px 10px 0;">
|
||||
<?= Html::submitButton('<i class="fa fa-check"></i>', [
|
||||
'class' => 'btn btn-default btn-sm',
|
||||
'class' => 'animal-inline-top-save-action',
|
||||
'title' => Yii::t('AnimalManagementModule.base', 'Save Medical Visit'),
|
||||
'form' => $medicalFormId,
|
||||
]) ?>
|
||||
<?php if ($showTopCancel): ?>
|
||||
<?= Html::button('<i class="fa fa-times"></i>', [
|
||||
'type' => 'button',
|
||||
'class' => 'btn btn-default btn-sm',
|
||||
'id' => 'medical-inline-add-cancel-icon',
|
||||
'class' => 'animal-inline-top-save-action',
|
||||
'title' => Yii::t('AnimalManagementModule.base', 'Cancel'),
|
||||
'type' => 'button',
|
||||
]) ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
@@ -289,19 +345,30 @@ CSS
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Medical Visit') ?></strong></div>
|
||||
<div class="panel-heading">
|
||||
<a data-toggle="collapse" class="collapsed" href="#medical-inline-section-visit" aria-expanded="false" aria-controls="medical-inline-section-visit">
|
||||
<strong><?= Yii::t('AnimalManagementModule.base', 'Medical Visit') ?></strong>
|
||||
</a>
|
||||
</div>
|
||||
<div id="medical-inline-section-visit" class="panel-collapse collapse" aria-expanded="false">
|
||||
<div class="panel-body" style="padding-bottom:8px;">
|
||||
<div class="row">
|
||||
<div class="col-sm-6"><?= $form->field($model, 'visit_at')->input('datetime-local') ?></div>
|
||||
<div class="col-sm-6"><?= $form->field($model, 'visit_at')->input('datetime-local', ['value' => $visitAtInputValue]) ?></div>
|
||||
<div class="col-sm-6"><?= $form->field($model, 'provider_name') ?></div>
|
||||
</div>
|
||||
<?= $form->field($model, 'notes')->textarea(['rows' => 3]) ?>
|
||||
<?= $form->field($model, 'recommendations')->textarea(['rows' => 3]) ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Vitals') ?></strong></div>
|
||||
<div class="panel-heading">
|
||||
<a data-toggle="collapse" class="collapsed" href="#medical-inline-section-vitals" aria-expanded="false" aria-controls="medical-inline-section-vitals">
|
||||
<strong><?= Yii::t('AnimalManagementModule.base', 'Vitals') ?></strong>
|
||||
</a>
|
||||
</div>
|
||||
<div id="medical-inline-section-vitals" class="panel-collapse collapse" aria-expanded="false">
|
||||
<div class="panel-body" style="padding-bottom:8px;">
|
||||
<div class="row">
|
||||
<div class="col-sm-3"><?= $renderCustomField('weight', $model, $customDefinitions) ?></div>
|
||||
@@ -311,25 +378,43 @@ CSS
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Conditions') ?></strong></div>
|
||||
<div class="panel-heading">
|
||||
<a data-toggle="collapse" class="collapsed" href="#medical-inline-section-conditions" aria-expanded="false" aria-controls="medical-inline-section-conditions">
|
||||
<strong><?= Yii::t('AnimalManagementModule.base', 'Conditions') ?></strong>
|
||||
</a>
|
||||
</div>
|
||||
<div id="medical-inline-section-conditions" class="panel-collapse collapse" aria-expanded="false">
|
||||
<div class="panel-body" style="padding-bottom:8px;">
|
||||
<?= $renderCustomField('chronic_conditions', $model, $customDefinitions) ?>
|
||||
<?= $renderCustomField('acute_conditions', $model, $customDefinitions) ?>
|
||||
<?= $renderCustomField('special_needs', $model, $customDefinitions) ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Medical Visit Detail') ?></strong></div>
|
||||
<div class="panel-heading">
|
||||
<a data-toggle="collapse" class="collapsed" href="#medical-inline-section-detail" aria-expanded="false" aria-controls="medical-inline-section-detail">
|
||||
<strong><?= Yii::t('AnimalManagementModule.base', 'Medical Visit Detail') ?></strong>
|
||||
</a>
|
||||
</div>
|
||||
<div id="medical-inline-section-detail" class="panel-collapse collapse" aria-expanded="false">
|
||||
<div class="panel-body" style="padding-bottom:8px;">
|
||||
<?= $renderCustomField('date_of_most_recent_medical_visit', $model, $customDefinitions) ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Physician') ?></strong></div>
|
||||
<div class="panel-heading">
|
||||
<a data-toggle="collapse" class="collapsed" href="#medical-inline-section-physician" aria-expanded="false" aria-controls="medical-inline-section-physician">
|
||||
<strong><?= Yii::t('AnimalManagementModule.base', 'Physician') ?></strong>
|
||||
</a>
|
||||
</div>
|
||||
<div id="medical-inline-section-physician" class="panel-collapse collapse" aria-expanded="false">
|
||||
<div class="panel-body" style="padding-bottom:8px;">
|
||||
<div class="row">
|
||||
<div class="col-sm-6"><?= $renderCustomField('physician_name', $model, $customDefinitions) ?></div>
|
||||
@@ -344,6 +429,7 @@ CSS
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Social Post') ?></strong></div>
|
||||
@@ -355,23 +441,23 @@ CSS
|
||||
|
||||
<?php if (!empty($remainingDefinitions)): ?>
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Additional Details') ?></strong></div>
|
||||
<div class="panel-heading">
|
||||
<a data-toggle="collapse" class="collapsed" href="#medical-inline-section-additional" aria-expanded="false" aria-controls="medical-inline-section-additional">
|
||||
<strong><?= Yii::t('AnimalManagementModule.base', 'Additional Details') ?></strong>
|
||||
</a>
|
||||
</div>
|
||||
<div id="medical-inline-section-additional" class="panel-collapse collapse" aria-expanded="false">
|
||||
<div class="panel-body" style="padding-bottom:8px;">
|
||||
<?php foreach ($remainingDefinitions as $fieldKey => $definition): ?>
|
||||
<?= $renderCustomField($fieldKey, $model, $remainingDefinitions) ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?= Button::save(Yii::t('AnimalManagementModule.base', 'Save Medical Visit'))->submit() ?>
|
||||
<?php if ($isInline): ?>
|
||||
<?= Html::button(Yii::t('AnimalManagementModule.base', 'Cancel'), [
|
||||
'type' => 'button',
|
||||
'class' => 'btn btn-default',
|
||||
'id' => 'medical-inline-add-cancel',
|
||||
]) ?>
|
||||
<?php else: ?>
|
||||
<?php if (!$isInline): ?>
|
||||
<?= Button::asLink(Yii::t('AnimalManagementModule.base', 'Cancel'))
|
||||
->link(($returnTo ?? 'medical-visits') === 'medical-visits'
|
||||
? $space->createUrl('/animal_management/animals/medical-visits', ['id' => $animal->id])
|
||||
@@ -507,11 +593,32 @@ if ($isInline) {
|
||||
]);
|
||||
|
||||
$this->registerJs(<<<JS
|
||||
$(document).on('click', '#medical-inline-add-cancel, #medical-inline-add-cancel-icon', function() {
|
||||
(function() {
|
||||
function postInlineCancel() {
|
||||
if (window.parent && window.parent !== window) {
|
||||
window.parent.postMessage($cancelPayload, '*');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (window.jQuery) {
|
||||
window.jQuery(document).on('click', '#medical-inline-add-cancel, #medical-inline-add-cancel-icon', function() {
|
||||
postInlineCancel();
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('click', function(event) {
|
||||
var target = event.target;
|
||||
if (!target || !target.closest) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!target.closest('#medical-inline-add-cancel, #medical-inline-add-cancel-icon')) {
|
||||
return;
|
||||
}
|
||||
|
||||
postInlineCancel();
|
||||
}, false);
|
||||
})();
|
||||
JS
|
||||
, \yii\web\View::POS_END);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ use yii\helpers\Json;
|
||||
/* @var bool $isInline */
|
||||
|
||||
$isInline = isset($isInline) ? (bool)$isInline : false;
|
||||
$showTopCancel = (string)Yii::$app->request->get('showTopCancel', '0') === '1';
|
||||
|
||||
$renderCustomField = static function (string $fieldKey, AnimalProgressUpdateForm $formModel, array $definitions): string {
|
||||
if (!isset($definitions[$fieldKey])) {
|
||||
@@ -132,6 +133,18 @@ $this->registerCss(<<<CSS
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.inline-add-shell .panel.panel-default > .panel-heading a {
|
||||
color: inherit;
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.inline-add-shell .panel.panel-default > .panel-heading a:hover,
|
||||
.inline-add-shell .panel.panel-default > .panel-heading a:focus {
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.inline-add-shell,
|
||||
.inline-add-shell .panel-body,
|
||||
.inline-add-shell .control-label,
|
||||
@@ -164,6 +177,31 @@ $this->registerCss(<<<CSS
|
||||
.inline-add-shell select.form-control option {
|
||||
color: #0f1b2a;
|
||||
}
|
||||
|
||||
.inline-add-shell .animal-inline-top-save-action {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
padding: 0;
|
||||
border-radius: 999px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.36);
|
||||
background: rgba(15, 23, 42, 0.72);
|
||||
color: #f8fafc;
|
||||
cursor: pointer;
|
||||
line-height: 1;
|
||||
font-size: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28);
|
||||
}
|
||||
|
||||
.inline-add-shell .animal-inline-top-save-action:hover,
|
||||
.inline-add-shell .animal-inline-top-save-action:focus {
|
||||
background: rgba(30, 41, 59, 0.86);
|
||||
border-color: rgba(255, 255, 255, 0.5);
|
||||
color: #f8fafc;
|
||||
outline: none;
|
||||
}
|
||||
CSS
|
||||
);
|
||||
|
||||
@@ -173,6 +211,13 @@ html, body {
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
background: transparent !important;
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
}
|
||||
|
||||
html::-webkit-scrollbar, body::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
body > .panel:first-child {
|
||||
@@ -195,25 +240,32 @@ CSS
|
||||
<?= Html::hiddenInput('returnTo', (string)($returnTo ?? 'progress-updates')) ?>
|
||||
|
||||
<?php if ($isInline): ?>
|
||||
<div style="display:flex;justify-content:flex-end;gap:8px;margin-bottom:10px;">
|
||||
<div class="animal-inline-top-actions" style="display:flex;justify-content:flex-end;gap:8px;margin:0 38px 10px 0;">
|
||||
<?= Html::submitButton('<i class="fa fa-check"></i>', [
|
||||
'class' => 'btn btn-default btn-sm',
|
||||
'class' => 'animal-inline-top-save-action',
|
||||
'title' => Yii::t('AnimalManagementModule.base', 'Save Progress Update'),
|
||||
'form' => $progressFormId,
|
||||
]) ?>
|
||||
<?php if ($showTopCancel): ?>
|
||||
<?= Html::button('<i class="fa fa-times"></i>', [
|
||||
'type' => 'button',
|
||||
'class' => 'btn btn-default btn-sm',
|
||||
'id' => 'progress-inline-add-cancel-icon',
|
||||
'class' => 'animal-inline-top-save-action',
|
||||
'title' => Yii::t('AnimalManagementModule.base', 'Cancel'),
|
||||
'type' => 'button',
|
||||
]) ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?= $form->errorSummary($model, ['showAllErrors' => true]) ?>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Media') ?></strong></div>
|
||||
<div class="panel-heading">
|
||||
<a data-toggle="collapse" href="#progress-inline-section-media" aria-expanded="true" aria-controls="progress-inline-section-media">
|
||||
<strong><?= Yii::t('AnimalManagementModule.base', 'Media') ?></strong>
|
||||
</a>
|
||||
</div>
|
||||
<div id="progress-inline-section-media" class="panel-collapse collapse in" aria-expanded="true">
|
||||
<div class="panel-body" style="padding-bottom:8px;">
|
||||
<input type="hidden" id="progress-media-gallery-path" name="progressMediaGalleryPath" value="<?= Html::encode($currentMediaReference) ?>">
|
||||
<div class="row">
|
||||
@@ -241,9 +293,15 @@ CSS
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Progress Update') ?></strong></div>
|
||||
<div class="panel-heading">
|
||||
<a data-toggle="collapse" href="#progress-inline-section-update" aria-expanded="true" aria-controls="progress-inline-section-update">
|
||||
<strong><?= Yii::t('AnimalManagementModule.base', 'Progress Update') ?></strong>
|
||||
</a>
|
||||
</div>
|
||||
<div id="progress-inline-section-update" class="panel-collapse collapse in" aria-expanded="true">
|
||||
<div class="panel-body" style="padding-bottom:8px;">
|
||||
<div class="row">
|
||||
<div class="col-sm-4"><?= $form->field($model, 'weight') ?></div>
|
||||
@@ -255,24 +313,37 @@ CSS
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Notes') ?></strong></div>
|
||||
<div class="panel-heading">
|
||||
<a data-toggle="collapse" href="#progress-inline-section-notes" aria-expanded="true" aria-controls="progress-inline-section-notes">
|
||||
<strong><?= Yii::t('AnimalManagementModule.base', 'Notes') ?></strong>
|
||||
</a>
|
||||
</div>
|
||||
<div id="progress-inline-section-notes" class="panel-collapse collapse in" aria-expanded="true">
|
||||
<div class="panel-body" style="padding-bottom:8px;">
|
||||
<?= $renderCustomField('progress_notes', $model, $customDefinitions) ?>
|
||||
<?= $renderCustomField('routine_updates', $model, $customDefinitions) ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($otherCustomDefinitions)): ?>
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Additional Details') ?></strong></div>
|
||||
<div class="panel-heading">
|
||||
<a data-toggle="collapse" href="#progress-inline-section-additional" aria-expanded="true" aria-controls="progress-inline-section-additional">
|
||||
<strong><?= Yii::t('AnimalManagementModule.base', 'Additional Details') ?></strong>
|
||||
</a>
|
||||
</div>
|
||||
<div id="progress-inline-section-additional" class="panel-collapse collapse in" aria-expanded="true">
|
||||
<div class="panel-body" style="padding-bottom:8px;">
|
||||
<?php foreach ($otherCustomDefinitions as $fieldKey => $definition): ?>
|
||||
<?= $renderCustomField($fieldKey, $model, $otherCustomDefinitions) ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
@@ -316,13 +387,7 @@ CSS
|
||||
</div>
|
||||
|
||||
<?= Button::save(Yii::t('AnimalManagementModule.base', 'Save Progress Update'))->submit() ?>
|
||||
<?php if ($isInline): ?>
|
||||
<?= Html::button(Yii::t('AnimalManagementModule.base', 'Cancel'), [
|
||||
'type' => 'button',
|
||||
'class' => 'btn btn-default',
|
||||
'id' => 'progress-inline-add-cancel',
|
||||
]) ?>
|
||||
<?php else: ?>
|
||||
<?php if (!$isInline): ?>
|
||||
<?= Button::asLink(Yii::t('AnimalManagementModule.base', 'Cancel'))
|
||||
->link(($returnTo ?? 'progress-updates') === 'progress-updates'
|
||||
? $space->createUrl('/animal_management/animals/progress-updates', ['id' => $animal->id])
|
||||
@@ -434,11 +499,32 @@ if ($isInline) {
|
||||
]);
|
||||
|
||||
$this->registerJs(<<<JS
|
||||
$(document).on('click', '#progress-inline-add-cancel, #progress-inline-add-cancel-icon', function() {
|
||||
(function() {
|
||||
function postInlineCancel() {
|
||||
if (window.parent && window.parent !== window) {
|
||||
window.parent.postMessage($cancelPayload, '*');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (window.jQuery) {
|
||||
window.jQuery(document).on('click', '#progress-inline-add-cancel, #progress-inline-add-cancel-icon', function() {
|
||||
postInlineCancel();
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('click', function(event) {
|
||||
var target = event.target;
|
||||
if (!target || !target.closest) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!target.closest('#progress-inline-add-cancel, #progress-inline-add-cancel-icon')) {
|
||||
return;
|
||||
}
|
||||
|
||||
postInlineCancel();
|
||||
}, false);
|
||||
})();
|
||||
JS
|
||||
, \yii\web\View::POS_END);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,18 @@ use yii\helpers\Html;
|
||||
/* @var Space $space */
|
||||
/* @var bool $isEdit */
|
||||
/* @var Animal|null $animal */
|
||||
/* @var bool $showIntakeGoalSection */
|
||||
|
||||
$showIntakeGoalSection = isset($showIntakeGoalSection) ? (bool)$showIntakeGoalSection : false;
|
||||
$intakeGoalInput = Yii::$app->request->post('IntakeGoal', []);
|
||||
if (!is_array($intakeGoalInput)) {
|
||||
$intakeGoalInput = [];
|
||||
}
|
||||
$intakeGoalEnabled = !empty($isEdit) ? false : ((int)($intakeGoalInput['enabled'] ?? 0) === 1);
|
||||
$intakeGoalTitle = trim((string)($intakeGoalInput['title'] ?? ''));
|
||||
$intakeGoalTargetAmount = trim((string)($intakeGoalInput['target_amount'] ?? ''));
|
||||
$intakeGoalDescription = trim((string)($intakeGoalInput['description'] ?? ''));
|
||||
$intakeGoalIsActive = !empty($isEdit) ? true : ((int)($intakeGoalInput['is_active'] ?? 1) === 1);
|
||||
?>
|
||||
|
||||
<div class="panel panel-default">
|
||||
@@ -215,6 +227,41 @@ use yii\helpers\Html;
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<?php if (empty($isEdit) && $showIntakeGoalSection): ?>
|
||||
<div class="panel panel-default" style="margin-bottom:14px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Intake Donation Goal') ?></strong></div>
|
||||
<div class="panel-body" style="padding-bottom:8px;">
|
||||
<div class="checkbox" style="margin-top:0;">
|
||||
<label>
|
||||
<input type="checkbox" name="IntakeGoal[enabled]" value="1" id="intake-goal-enabled" <?= $intakeGoalEnabled ? 'checked' : '' ?>>
|
||||
<?= Yii::t('AnimalManagementModule.base', 'Create a donation goal for this animal on intake') ?>
|
||||
</label>
|
||||
</div>
|
||||
<div id="intake-goal-fields" style="display:<?= $intakeGoalEnabled ? 'block' : 'none' ?>;">
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="intake-goal-title"><?= Yii::t('AnimalManagementModule.base', 'Goal Title') ?></label>
|
||||
<input type="text" id="intake-goal-title" name="IntakeGoal[title]" class="form-control" maxlength="190" value="<?= Html::encode($intakeGoalTitle) ?>" placeholder="<?= Html::encode(Yii::t('AnimalManagementModule.base', 'Example: {animalName} Care Fund', ['animalName' => 'Animal'])) ?>">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="intake-goal-target"><?= Yii::t('AnimalManagementModule.base', 'Target Amount') ?></label>
|
||||
<input type="number" id="intake-goal-target" name="IntakeGoal[target_amount]" class="form-control" min="1" step="1" value="<?= Html::encode($intakeGoalTargetAmount) ?>" placeholder="1500">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="intake-goal-description"><?= Yii::t('AnimalManagementModule.base', 'Goal Description') ?></label>
|
||||
<textarea id="intake-goal-description" name="IntakeGoal[description]" class="form-control" rows="3" placeholder="<?= Html::encode(Yii::t('AnimalManagementModule.base', 'Optional context for supporters.')) ?>"><?= Html::encode($intakeGoalDescription) ?></textarea>
|
||||
</div>
|
||||
<div class="checkbox" style="margin-bottom:0;">
|
||||
<label>
|
||||
<input type="hidden" name="IntakeGoal[is_active]" value="0">
|
||||
<input type="checkbox" name="IntakeGoal[is_active]" value="1" <?= $intakeGoalIsActive ? 'checked' : '' ?>>
|
||||
<?= Yii::t('AnimalManagementModule.base', 'Goal is active immediately') ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:14px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Previous Owner') ?></strong></div>
|
||||
<div class="panel-body" style="padding-bottom:8px;">
|
||||
@@ -274,7 +321,7 @@ use yii\helpers\Html;
|
||||
|
||||
<?= Button::save(!empty($isEdit)
|
||||
? Yii::t('AnimalManagementModule.base', 'Save Changes')
|
||||
: Yii::t('AnimalManagementModule.base', 'Create Animal'))->submit() ?>
|
||||
: Yii::t('AnimalManagementModule.base', 'Complete Intake'))->submit() ?>
|
||||
<?= Button::asLink(Yii::t('AnimalManagementModule.base', 'Cancel'))->link(
|
||||
!empty($isEdit) && $animal instanceof Animal
|
||||
? $space->createUrl('/animal_management/animals/view', ['id' => $animal->id])
|
||||
@@ -306,7 +353,7 @@ use yii\helpers\Html;
|
||||
<?= Yii::t('AnimalManagementModule.base', 'Your image preview updates immediately. Final save happens when you click {action} at the bottom of this intake form.', [
|
||||
'action' => !empty($isEdit)
|
||||
? Yii::t('AnimalManagementModule.base', 'Save Changes')
|
||||
: Yii::t('AnimalManagementModule.base', 'Create Animal'),
|
||||
: Yii::t('AnimalManagementModule.base', 'Complete Intake'),
|
||||
]) ?>
|
||||
</div>
|
||||
<?php if (!empty($galleryImageUrls)): ?>
|
||||
@@ -350,7 +397,7 @@ use yii\helpers\Html;
|
||||
<?= Yii::t('AnimalManagementModule.base', 'Your image preview updates immediately. Final save happens when you click {action} at the bottom of this intake form.', [
|
||||
'action' => !empty($isEdit)
|
||||
? Yii::t('AnimalManagementModule.base', 'Save Changes')
|
||||
: Yii::t('AnimalManagementModule.base', 'Create Animal'),
|
||||
: Yii::t('AnimalManagementModule.base', 'Complete Intake'),
|
||||
]) ?>
|
||||
</div>
|
||||
<?php if (!empty($galleryImageUrls)): ?>
|
||||
@@ -521,6 +568,14 @@ $this->registerJs(<<<JS
|
||||
}
|
||||
});
|
||||
|
||||
$('#intake-goal-enabled').on('change', function() {
|
||||
if ($(this).is(':checked')) {
|
||||
$('#intake-goal-fields').slideDown(120);
|
||||
} else {
|
||||
$('#intake-goal-fields').slideUp(120);
|
||||
}
|
||||
});
|
||||
|
||||
$('#animal-cover-image-manage-modal').on('shown.bs.modal', function() {
|
||||
markSelectedThumb('cover', $('#animalform-coverimagegallerypath').val());
|
||||
});
|
||||
|
||||
@@ -19,6 +19,7 @@ use yii\helpers\Json;
|
||||
/* @var bool $isInline */
|
||||
|
||||
$isInline = isset($isInline) ? (bool)$isInline : false;
|
||||
$showTopCancel = (string)Yii::$app->request->get('showTopCancel', '0') === '1';
|
||||
|
||||
$hiddenMedicalKeys = [
|
||||
'second_physician_name',
|
||||
@@ -166,6 +167,18 @@ $this->registerCss(<<<CSS
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.inline-editor-shell .panel.panel-default > .panel-heading a {
|
||||
color: inherit;
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.inline-editor-shell .panel.panel-default > .panel-heading a:hover,
|
||||
.inline-editor-shell .panel.panel-default > .panel-heading a:focus {
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.inline-editor-shell,
|
||||
.inline-editor-shell .panel-body,
|
||||
.inline-editor-shell .control-label,
|
||||
@@ -198,6 +211,31 @@ $this->registerCss(<<<CSS
|
||||
.inline-editor-shell select.form-control option {
|
||||
color: #0f1b2a;
|
||||
}
|
||||
|
||||
.inline-editor-shell .animal-inline-top-save-action {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
padding: 0;
|
||||
border-radius: 999px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.36);
|
||||
background: rgba(15, 23, 42, 0.72);
|
||||
color: #f8fafc;
|
||||
cursor: pointer;
|
||||
line-height: 1;
|
||||
font-size: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28);
|
||||
}
|
||||
|
||||
.inline-editor-shell .animal-inline-top-save-action:hover,
|
||||
.inline-editor-shell .animal-inline-top-save-action:focus {
|
||||
background: rgba(30, 41, 59, 0.86);
|
||||
border-color: rgba(255, 255, 255, 0.5);
|
||||
color: #f8fafc;
|
||||
outline: none;
|
||||
}
|
||||
CSS
|
||||
);
|
||||
|
||||
@@ -207,6 +245,13 @@ html, body {
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
background: transparent !important;
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
}
|
||||
|
||||
html::-webkit-scrollbar, body::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
body > .panel:first-child {
|
||||
@@ -229,18 +274,20 @@ CSS
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;gap:12px;">
|
||||
<span><?= Yii::t('AnimalManagementModule.base', '<strong>Edit</strong> Medical Visit') ?></span>
|
||||
<?php if ($isInline): ?>
|
||||
<span style="display:inline-flex;gap:8px;">
|
||||
<span class="animal-inline-top-actions" style="display:inline-flex;gap:8px;margin-right:38px;">
|
||||
<?= Html::submitButton('<i class="fa fa-check"></i>', [
|
||||
'class' => 'btn btn-default btn-sm',
|
||||
'class' => 'animal-inline-top-save-action',
|
||||
'title' => Yii::t('AnimalManagementModule.base', 'Save Medical Visit'),
|
||||
'form' => $medicalFormId,
|
||||
]) ?>
|
||||
<?php if ($showTopCancel): ?>
|
||||
<?= Html::button('<i class="fa fa-times"></i>', [
|
||||
'type' => 'button',
|
||||
'class' => 'btn btn-default btn-sm',
|
||||
'id' => 'medical-inline-cancel-icon',
|
||||
'class' => 'animal-inline-top-save-action',
|
||||
'title' => Yii::t('AnimalManagementModule.base', 'Cancel'),
|
||||
'type' => 'button',
|
||||
]) ?>
|
||||
<?php endif; ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
@@ -259,7 +306,12 @@ CSS
|
||||
<?= $form->errorSummary($model, ['showAllErrors' => true]) ?>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Visit') ?></strong></div>
|
||||
<div class="panel-heading">
|
||||
<a data-toggle="collapse" href="#edit-medical-section-visit" aria-expanded="true" aria-controls="edit-medical-section-visit">
|
||||
<strong><?= Yii::t('AnimalManagementModule.base', 'Visit') ?></strong>
|
||||
</a>
|
||||
</div>
|
||||
<div id="edit-medical-section-visit" class="panel-collapse collapse in" aria-expanded="true">
|
||||
<div class="panel-body" style="padding-bottom:8px;">
|
||||
<div class="row">
|
||||
<div class="col-sm-6"><?= $form->field($model, 'visit_at')->input('datetime-local') ?></div>
|
||||
@@ -269,9 +321,15 @@ CSS
|
||||
<?= $form->field($model, 'recommendations')->textarea(['rows' => 3]) ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Vitals') ?></strong></div>
|
||||
<div class="panel-heading">
|
||||
<a data-toggle="collapse" href="#edit-medical-section-vitals" aria-expanded="true" aria-controls="edit-medical-section-vitals">
|
||||
<strong><?= Yii::t('AnimalManagementModule.base', 'Vitals') ?></strong>
|
||||
</a>
|
||||
</div>
|
||||
<div id="edit-medical-section-vitals" class="panel-collapse collapse in" aria-expanded="true">
|
||||
<div class="panel-body" style="padding-bottom:8px;">
|
||||
<div class="row">
|
||||
<div class="col-sm-3"><?= $renderCustomField('weight', $model, $customDefinitions) ?></div>
|
||||
@@ -281,25 +339,43 @@ CSS
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Conditions') ?></strong></div>
|
||||
<div class="panel-heading">
|
||||
<a data-toggle="collapse" href="#edit-medical-section-conditions" aria-expanded="true" aria-controls="edit-medical-section-conditions">
|
||||
<strong><?= Yii::t('AnimalManagementModule.base', 'Conditions') ?></strong>
|
||||
</a>
|
||||
</div>
|
||||
<div id="edit-medical-section-conditions" class="panel-collapse collapse in" aria-expanded="true">
|
||||
<div class="panel-body" style="padding-bottom:8px;">
|
||||
<?= $renderCustomField('chronic_conditions', $model, $customDefinitions) ?>
|
||||
<?= $renderCustomField('acute_conditions', $model, $customDefinitions) ?>
|
||||
<?= $renderCustomField('special_needs', $model, $customDefinitions) ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Medical Visit Detail') ?></strong></div>
|
||||
<div class="panel-heading">
|
||||
<a data-toggle="collapse" href="#edit-medical-section-detail" aria-expanded="true" aria-controls="edit-medical-section-detail">
|
||||
<strong><?= Yii::t('AnimalManagementModule.base', 'Medical Visit Detail') ?></strong>
|
||||
</a>
|
||||
</div>
|
||||
<div id="edit-medical-section-detail" class="panel-collapse collapse in" aria-expanded="true">
|
||||
<div class="panel-body" style="padding-bottom:8px;">
|
||||
<?= $renderCustomField('date_of_most_recent_medical_visit', $model, $customDefinitions) ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Media') ?></strong></div>
|
||||
<div class="panel-heading">
|
||||
<a data-toggle="collapse" href="#edit-medical-section-media" aria-expanded="true" aria-controls="edit-medical-section-media">
|
||||
<strong><?= Yii::t('AnimalManagementModule.base', 'Media') ?></strong>
|
||||
</a>
|
||||
</div>
|
||||
<div id="edit-medical-section-media" class="panel-collapse collapse in" aria-expanded="true">
|
||||
<div class="panel-body" style="padding-bottom:8px;">
|
||||
<div class="row">
|
||||
<div class="col-sm-4" style="margin-bottom:8px;">
|
||||
@@ -325,9 +401,15 @@ CSS
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Physician') ?></strong></div>
|
||||
<div class="panel-heading">
|
||||
<a data-toggle="collapse" href="#edit-medical-section-physician" aria-expanded="true" aria-controls="edit-medical-section-physician">
|
||||
<strong><?= Yii::t('AnimalManagementModule.base', 'Physician') ?></strong>
|
||||
</a>
|
||||
</div>
|
||||
<div id="edit-medical-section-physician" class="panel-collapse collapse in" aria-expanded="true">
|
||||
<div class="panel-body" style="padding-bottom:8px;">
|
||||
<div class="row">
|
||||
<div class="col-sm-6"><?= $renderCustomField('physician_name', $model, $customDefinitions) ?></div>
|
||||
@@ -342,6 +424,7 @@ CSS
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Social Post') ?></strong></div>
|
||||
@@ -353,23 +436,23 @@ CSS
|
||||
|
||||
<?php if (!empty($remainingDefinitions)): ?>
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Additional Details') ?></strong></div>
|
||||
<div class="panel-heading">
|
||||
<a data-toggle="collapse" href="#edit-medical-section-additional" aria-expanded="true" aria-controls="edit-medical-section-additional">
|
||||
<strong><?= Yii::t('AnimalManagementModule.base', 'Additional Details') ?></strong>
|
||||
</a>
|
||||
</div>
|
||||
<div id="edit-medical-section-additional" class="panel-collapse collapse in" aria-expanded="true">
|
||||
<div class="panel-body" style="padding-bottom:8px;">
|
||||
<?php foreach ($remainingDefinitions as $fieldKey => $definition): ?>
|
||||
<?= $renderCustomField($fieldKey, $model, $remainingDefinitions) ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?= Button::save(Yii::t('AnimalManagementModule.base', 'Save Medical Visit'))->submit() ?>
|
||||
<?php if ($isInline): ?>
|
||||
<?= Html::button(Yii::t('AnimalManagementModule.base', 'Cancel'), [
|
||||
'type' => 'button',
|
||||
'class' => 'btn btn-default',
|
||||
'id' => 'medical-inline-cancel',
|
||||
]) ?>
|
||||
<?php else: ?>
|
||||
<?php if (!$isInline): ?>
|
||||
<?= Button::asLink(Yii::t('AnimalManagementModule.base', 'Cancel'))
|
||||
->link(($returnTo ?? 'view') === 'medical-visits'
|
||||
? $space->createUrl('/animal_management/animals/medical-visits', ['id' => $animal->id])
|
||||
@@ -486,11 +569,32 @@ if ($isInline) {
|
||||
]);
|
||||
|
||||
$this->registerJs(<<<JS
|
||||
$(document).on('click', '#medical-inline-cancel, #medical-inline-cancel-icon', function() {
|
||||
(function() {
|
||||
function postInlineCancel() {
|
||||
if (window.parent && window.parent !== window) {
|
||||
window.parent.postMessage($cancelPayload, '*');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (window.jQuery) {
|
||||
window.jQuery(document).on('click', '#medical-inline-cancel, #medical-inline-cancel-icon', function() {
|
||||
postInlineCancel();
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('click', function(event) {
|
||||
var target = event.target;
|
||||
if (!target || !target.closest) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!target.closest('#medical-inline-cancel, #medical-inline-cancel-icon')) {
|
||||
return;
|
||||
}
|
||||
|
||||
postInlineCancel();
|
||||
}, false);
|
||||
})();
|
||||
JS
|
||||
, \yii\web\View::POS_END);
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ use yii\helpers\Json;
|
||||
/* @var bool $isInline */
|
||||
|
||||
$isInline = isset($isInline) ? (bool)$isInline : false;
|
||||
$showTopCancel = (string)Yii::$app->request->get('showTopCancel', '0') === '1';
|
||||
|
||||
$renderCustomField = static function (string $fieldKey, AnimalProgressUpdateForm $formModel, array $definitions): string {
|
||||
if (!isset($definitions[$fieldKey])) {
|
||||
@@ -126,6 +127,18 @@ $this->registerCss(<<<CSS
|
||||
border-color: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.inline-editor-shell .panel.panel-default > .panel-heading a {
|
||||
color: inherit;
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.inline-editor-shell .panel.panel-default > .panel-heading a:hover,
|
||||
.inline-editor-shell .panel.panel-default > .panel-heading a:focus {
|
||||
color: #ffffff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.inline-editor-shell,
|
||||
.inline-editor-shell .panel-body,
|
||||
.inline-editor-shell .control-label,
|
||||
@@ -158,6 +171,31 @@ $this->registerCss(<<<CSS
|
||||
.inline-editor-shell select.form-control option {
|
||||
color: #0f1b2a;
|
||||
}
|
||||
|
||||
.inline-editor-shell .animal-inline-top-save-action {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
padding: 0;
|
||||
border-radius: 999px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.36);
|
||||
background: rgba(15, 23, 42, 0.72);
|
||||
color: #f8fafc;
|
||||
cursor: pointer;
|
||||
line-height: 1;
|
||||
font-size: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28);
|
||||
}
|
||||
|
||||
.inline-editor-shell .animal-inline-top-save-action:hover,
|
||||
.inline-editor-shell .animal-inline-top-save-action:focus {
|
||||
background: rgba(30, 41, 59, 0.86);
|
||||
border-color: rgba(255, 255, 255, 0.5);
|
||||
color: #f8fafc;
|
||||
outline: none;
|
||||
}
|
||||
CSS
|
||||
);
|
||||
|
||||
@@ -167,6 +205,13 @@ html, body {
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
background: transparent !important;
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
}
|
||||
|
||||
html::-webkit-scrollbar, body::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
body > .panel:first-child {
|
||||
@@ -182,18 +227,20 @@ CSS
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;gap:12px;">
|
||||
<span><?= Yii::t('AnimalManagementModule.base', '<strong>Edit</strong> Progress Update') ?></span>
|
||||
<?php if ($isInline): ?>
|
||||
<span style="display:inline-flex;gap:8px;">
|
||||
<span class="animal-inline-top-actions" style="display:inline-flex;gap:8px;margin-right:38px;">
|
||||
<?= Html::submitButton('<i class="fa fa-check"></i>', [
|
||||
'class' => 'btn btn-default btn-sm',
|
||||
'class' => 'animal-inline-top-save-action',
|
||||
'title' => Yii::t('AnimalManagementModule.base', 'Save Progress Update'),
|
||||
'form' => $progressFormId,
|
||||
]) ?>
|
||||
<?php if ($showTopCancel): ?>
|
||||
<?= Html::button('<i class="fa fa-times"></i>', [
|
||||
'type' => 'button',
|
||||
'class' => 'btn btn-default btn-sm',
|
||||
'id' => 'progress-inline-cancel-icon',
|
||||
'class' => 'animal-inline-top-save-action',
|
||||
'title' => Yii::t('AnimalManagementModule.base', 'Cancel'),
|
||||
'type' => 'button',
|
||||
]) ?>
|
||||
<?php endif; ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
@@ -211,7 +258,12 @@ CSS
|
||||
<?= $form->errorSummary($model, ['showAllErrors' => true]) ?>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Progress Update') ?></strong></div>
|
||||
<div class="panel-heading">
|
||||
<a data-toggle="collapse" href="#edit-progress-section-update" aria-expanded="true" aria-controls="edit-progress-section-update">
|
||||
<strong><?= Yii::t('AnimalManagementModule.base', 'Progress Update') ?></strong>
|
||||
</a>
|
||||
</div>
|
||||
<div id="edit-progress-section-update" class="panel-collapse collapse in" aria-expanded="true">
|
||||
<div class="panel-body" style="padding-bottom:8px;">
|
||||
<div class="row">
|
||||
<div class="col-sm-4"><?= $form->field($model, 'weight') ?></div>
|
||||
@@ -223,28 +275,46 @@ CSS
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Notes') ?></strong></div>
|
||||
<div class="panel-heading">
|
||||
<a data-toggle="collapse" href="#edit-progress-section-notes" aria-expanded="true" aria-controls="edit-progress-section-notes">
|
||||
<strong><?= Yii::t('AnimalManagementModule.base', 'Notes') ?></strong>
|
||||
</a>
|
||||
</div>
|
||||
<div id="edit-progress-section-notes" class="panel-collapse collapse in" aria-expanded="true">
|
||||
<div class="panel-body" style="padding-bottom:8px;">
|
||||
<?= $renderCustomField('progress_notes', $model, $customDefinitions) ?>
|
||||
<?= $renderCustomField('routine_updates', $model, $customDefinitions) ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php if (!empty($otherCustomDefinitions)): ?>
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Additional Details') ?></strong></div>
|
||||
<div class="panel-heading">
|
||||
<a data-toggle="collapse" href="#edit-progress-section-additional" aria-expanded="true" aria-controls="edit-progress-section-additional">
|
||||
<strong><?= Yii::t('AnimalManagementModule.base', 'Additional Details') ?></strong>
|
||||
</a>
|
||||
</div>
|
||||
<div id="edit-progress-section-additional" class="panel-collapse collapse in" aria-expanded="true">
|
||||
<div class="panel-body" style="padding-bottom:8px;">
|
||||
<?php foreach ($otherCustomDefinitions as $fieldKey => $definition): ?>
|
||||
<?= $renderCustomField($fieldKey, $model, $otherCustomDefinitions) ?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Media') ?></strong></div>
|
||||
<div class="panel-heading">
|
||||
<a data-toggle="collapse" href="#edit-progress-section-media" aria-expanded="true" aria-controls="edit-progress-section-media">
|
||||
<strong><?= Yii::t('AnimalManagementModule.base', 'Media') ?></strong>
|
||||
</a>
|
||||
</div>
|
||||
<div id="edit-progress-section-media" class="panel-collapse collapse in" aria-expanded="true">
|
||||
<div class="panel-body" style="padding-bottom:8px;">
|
||||
<input type="hidden" id="progress-media-gallery-path" name="progressMediaGalleryPath" value="<?= Html::encode($currentMediaReference) ?>">
|
||||
<div class="row">
|
||||
@@ -272,6 +342,7 @@ CSS
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default" style="margin-bottom:12px;">
|
||||
<div class="panel-heading"><strong><?= Yii::t('AnimalManagementModule.base', 'Social Post') ?></strong></div>
|
||||
@@ -314,13 +385,7 @@ CSS
|
||||
</div>
|
||||
|
||||
<?= Button::save(Yii::t('AnimalManagementModule.base', 'Save Progress Update'))->submit() ?>
|
||||
<?php if ($isInline): ?>
|
||||
<?= Html::button(Yii::t('AnimalManagementModule.base', 'Cancel'), [
|
||||
'type' => 'button',
|
||||
'class' => 'btn btn-default',
|
||||
'id' => 'progress-inline-cancel',
|
||||
]) ?>
|
||||
<?php else: ?>
|
||||
<?php if (!$isInline): ?>
|
||||
<?= Button::asLink(Yii::t('AnimalManagementModule.base', 'Cancel'))
|
||||
->link(($returnTo ?? 'view') === 'progress-updates'
|
||||
? $space->createUrl('/animal_management/animals/progress-updates', ['id' => $animal->id])
|
||||
@@ -413,11 +478,32 @@ if ($isInline) {
|
||||
]);
|
||||
|
||||
$this->registerJs(<<<JS
|
||||
$(document).on('click', '#progress-inline-cancel, #progress-inline-cancel-icon', function() {
|
||||
(function() {
|
||||
function postInlineCancel() {
|
||||
if (window.parent && window.parent !== window) {
|
||||
window.parent.postMessage($cancelPayload, '*');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (window.jQuery) {
|
||||
window.jQuery(document).on('click', '#progress-inline-cancel, #progress-inline-cancel-icon', function() {
|
||||
postInlineCancel();
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('click', function(event) {
|
||||
var target = event.target;
|
||||
if (!target || !target.closest) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!target.closest('#progress-inline-cancel, #progress-inline-cancel-icon')) {
|
||||
return;
|
||||
}
|
||||
|
||||
postInlineCancel();
|
||||
}, false);
|
||||
})();
|
||||
JS
|
||||
, \yii\web\View::POS_END);
|
||||
}
|
||||
|
||||
@@ -23,11 +23,14 @@ use yii\helpers\Html;
|
||||
/* @var array<int, AnimalMedicalVisit> $latestMedicalVisitByAnimal */
|
||||
/* @var array<int, string> $animalImageUrls */
|
||||
/* @var array<int, string> $transferAnimalImageUrls */
|
||||
/* @var array<int, mixed> $animalDonationGoalsByAnimal */
|
||||
/* @var array $tileFields */
|
||||
/* @var array<int, array> $tileFieldOverrides */
|
||||
/* @var Space $space */
|
||||
/* @var bool $canManage */
|
||||
|
||||
$isTabletFocusMode = ($viewMode === 'tablet') && ((string)Yii::$app->request->get('focus', '') === '1');
|
||||
|
||||
$currentParams = [
|
||||
'q' => $queryValue,
|
||||
'status' => $statusFilter,
|
||||
@@ -40,6 +43,13 @@ $currentParams = [
|
||||
|
||||
$buildUrl = static function (array $overrides) use ($space, $currentParams): string {
|
||||
$params = array_merge($currentParams, $overrides);
|
||||
|
||||
if (($params['view'] ?? '') !== 'tablet') {
|
||||
unset($params['focus']);
|
||||
} elseif (($params['focus'] ?? '') !== '1') {
|
||||
unset($params['focus']);
|
||||
}
|
||||
|
||||
return $space->createUrl('/animal_management/animals/index', $params);
|
||||
};
|
||||
|
||||
@@ -47,16 +57,70 @@ $sortUrl = static function (string $column) use ($buildUrl, $sortKey, $sortDirec
|
||||
$nextDirection = ($sortKey === $column && $sortDirection === 'asc') ? 'desc' : 'asc';
|
||||
return $buildUrl(['sort' => $column, 'direction' => $nextDirection, 'view' => 'table']);
|
||||
};
|
||||
|
||||
$showDonationSettingsLinks = $canManage && $space->moduleManager->isEnabled('donations');
|
||||
?>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<?php if ($isTabletFocusMode): ?>
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
overflow: hidden !important;
|
||||
}
|
||||
|
||||
#animals-index-panel.animal-focus-overlay {
|
||||
position: fixed !important;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
z-index: 9999;
|
||||
margin: 0 !important;
|
||||
border-radius: 0 !important;
|
||||
border: 0 !important;
|
||||
width: 100vw !important;
|
||||
max-width: 100vw !important;
|
||||
height: 100vh !important;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
#animals-index-panel.animal-focus-overlay .panel-heading {
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
#animals-index-panel.animal-focus-overlay .panel-body {
|
||||
flex: 1 1 auto;
|
||||
overflow-y: auto;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
}
|
||||
</style>
|
||||
<?php endif; ?>
|
||||
|
||||
<div id="animals-index-panel" class="panel panel-default<?= $isTabletFocusMode ? ' animal-focus-overlay' : '' ?>">
|
||||
<div class="panel-heading" style="display:flex;justify-content:space-between;align-items:center;">
|
||||
<span><?= Yii::t('AnimalManagementModule.base', '<strong>Animals</strong>') ?></span>
|
||||
<span style="display:flex;gap:8px;flex-wrap:wrap;align-items:center;">
|
||||
<?= Html::a('<i class="fa fa-th-large"></i>', $buildUrl(['view' => 'tiles']), [
|
||||
<?= Html::a('<i class="fa fa-tablet"></i>', $buildUrl(['view' => 'tablet', 'focus' => '1']), [
|
||||
'class' => 'btn btn-default btn-sm' . ($viewMode === 'tablet' ? ' active' : ''),
|
||||
'title' => Yii::t('AnimalManagementModule.base', 'Tablet View'),
|
||||
'aria-label' => Yii::t('AnimalManagementModule.base', 'Tablet View'),
|
||||
]) ?>
|
||||
<?= Html::a('<i class="fa fa-bars"></i>', $buildUrl(['view' => 'rows']), [
|
||||
'class' => 'btn btn-default btn-sm' . ($viewMode === 'rows' ? ' active' : ''),
|
||||
'title' => Yii::t('AnimalManagementModule.base', 'Row View'),
|
||||
'aria-label' => Yii::t('AnimalManagementModule.base', 'Row View'),
|
||||
]) ?>
|
||||
<?= Html::a('<i class="fa fa-columns"></i>', $buildUrl(['view' => 'tiles2']), [
|
||||
'class' => 'btn btn-default btn-sm' . ($viewMode === 'tiles2' ? ' active' : ''),
|
||||
'title' => Yii::t('AnimalManagementModule.base', '2-Column View'),
|
||||
'aria-label' => Yii::t('AnimalManagementModule.base', '2-Column View'),
|
||||
]) ?>
|
||||
<?= Html::a('<i class="fa fa-th"></i>', $buildUrl(['view' => 'tiles']), [
|
||||
'class' => 'btn btn-default btn-sm' . ($viewMode === 'tiles' ? ' active' : ''),
|
||||
'title' => Yii::t('AnimalManagementModule.base', 'Tile View'),
|
||||
'aria-label' => Yii::t('AnimalManagementModule.base', 'Tile View'),
|
||||
'title' => Yii::t('AnimalManagementModule.base', '3-Column View'),
|
||||
'aria-label' => Yii::t('AnimalManagementModule.base', '3-Column View'),
|
||||
]) ?>
|
||||
<?= Html::a('<i class="fa fa-table"></i>', $buildUrl(['view' => 'table']), [
|
||||
'class' => 'btn btn-default btn-sm' . ($viewMode === 'table' ? ' active' : ''),
|
||||
@@ -76,6 +140,9 @@ $sortUrl = static function (string $column) use ($buildUrl, $sortKey, $sortDirec
|
||||
<div class="panel-body">
|
||||
<form method="get" action="<?= Html::encode($space->createUrl('/animal_management/animals/index')) ?>" class="form-inline" style="margin-bottom:12px;display:flex;gap:8px;flex-wrap:wrap;">
|
||||
<input type="hidden" name="view" value="<?= Html::encode($viewMode) ?>">
|
||||
<?php if ($isTabletFocusMode): ?>
|
||||
<input type="hidden" name="focus" value="1">
|
||||
<?php endif; ?>
|
||||
<input type="hidden" name="sort" value="<?= Html::encode($sortKey) ?>">
|
||||
<input type="hidden" name="direction" value="<?= Html::encode($sortDirection) ?>">
|
||||
<?php foreach ($selectedColumns as $col): ?>
|
||||
@@ -125,12 +192,22 @@ $sortUrl = static function (string $column) use ($buildUrl, $sortKey, $sortDirec
|
||||
<?= Yii::t('AnimalManagementModule.base', 'No animal profiles yet. Create the first intake record to begin tracking.') ?>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<?php if ($viewMode === 'tiles'): ?>
|
||||
<?php if ($viewMode !== 'table'): ?>
|
||||
<?php
|
||||
$tileColumnClass = 'col-xs-12 col-sm-6 col-md-4';
|
||||
if ($viewMode === 'tiles2') {
|
||||
$tileColumnClass = 'col-xs-12 col-sm-6';
|
||||
} elseif ($viewMode === 'rows') {
|
||||
$tileColumnClass = 'col-xs-12';
|
||||
} elseif ($viewMode === 'tablet') {
|
||||
$tileColumnClass = 'col-xs-12';
|
||||
}
|
||||
?>
|
||||
<div class="row">
|
||||
<?php foreach ($animals as $animal): ?>
|
||||
<?php $animalId = (int)$animal->id; ?>
|
||||
<?php $lastMedical = $latestMedicalVisitByAnimal[$animalId] ?? null; ?>
|
||||
<div class="col-sm-6 col-md-4" style="margin-bottom:16px;">
|
||||
<div class="<?= Html::encode($tileColumnClass) ?>" style="margin-bottom:16px;">
|
||||
<?= $this->render('_tile', [
|
||||
'animal' => $animal,
|
||||
'contentContainer' => $space,
|
||||
@@ -138,6 +215,9 @@ $sortUrl = static function (string $column) use ($buildUrl, $sortKey, $sortDirec
|
||||
'imageUrl' => $animalImageUrls[$animalId] ?? '',
|
||||
'tileFields' => $tileFieldOverrides[$animalId] ?? $tileFields,
|
||||
'showMedicalIcon' => true,
|
||||
'showDonationSettingsButton' => $showDonationSettingsLinks,
|
||||
'existingDonationGoal' => $animalDonationGoalsByAnimal[$animalId] ?? null,
|
||||
'tileLayoutMode' => $viewMode,
|
||||
]) ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
@@ -205,6 +285,13 @@ $sortUrl = static function (string $column) use ($buildUrl, $sortKey, $sortDirec
|
||||
->link($space->createUrl('/animal_management/animals/medical-visits', ['id' => $animal->id])) ?>
|
||||
<?= Button::asLink(Yii::t('AnimalManagementModule.base', 'Progress'))
|
||||
->link($space->createUrl('/animal_management/animals/progress-updates', ['id' => $animal->id])) ?>
|
||||
<?php if ($showDonationSettingsLinks): ?>
|
||||
<?= Button::asLink(Yii::t('AnimalManagementModule.base', 'Donations'))
|
||||
->link($space->createUrl('/donations/settings', [
|
||||
'goalType' => 'animal',
|
||||
'targetAnimalId' => (int)$animal->id,
|
||||
])) ?>
|
||||
<?php endif; ?>
|
||||
<?php if ($canManage): ?>
|
||||
<?= Button::asLink(Yii::t('AnimalManagementModule.base', 'Edit'))
|
||||
->link($space->createUrl('/animal_management/animals/edit', ['id' => $animal->id])) ?>
|
||||
@@ -223,10 +310,11 @@ $sortUrl = static function (string $column) use ($buildUrl, $sortKey, $sortDirec
|
||||
<?php if ($canManage): ?>
|
||||
<hr>
|
||||
|
||||
<h4 id="incoming-transfers" style="margin-top:0;"><?= Yii::t('AnimalManagementModule.base', 'Incoming Transfer Requests') ?></h4>
|
||||
<?php if (empty($incomingTransfers)): ?>
|
||||
<div class="text-muted" style="margin-bottom:12px;"><?= Yii::t('AnimalManagementModule.base', 'No incoming requests.') ?></div>
|
||||
<?php else: ?>
|
||||
<?php $incomingTransfersHeading = empty($incomingTransfers)
|
||||
? Yii::t('AnimalManagementModule.base', 'No Incoming Transfers')
|
||||
: Yii::t('AnimalManagementModule.base', 'Incoming Transfer Requests'); ?>
|
||||
<h4 id="incoming-transfers" style="margin-top:0;"><?= Html::encode($incomingTransfersHeading) ?></h4>
|
||||
<?php if (!empty($incomingTransfers)): ?>
|
||||
<div class="row" style="margin-bottom:4px;">
|
||||
<?php foreach ($incomingTransfers as $transfer): ?>
|
||||
<?php
|
||||
|
||||
@@ -15,7 +15,7 @@ $payload = [
|
||||
$jsonPayload = json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
?>
|
||||
|
||||
<div class="panel panel-success" style="margin:10px;">
|
||||
<div class="panel panel-success" data-animal-inline-result="saved" data-animal-inline-collapse-id="<?= Html::encode((string)$collapseId) ?>" style="margin:10px;">
|
||||
<div class="panel-body" style="padding:12px;">
|
||||
<?= Html::encode(Yii::t('AnimalManagementModule.base', 'Saved. Updating section...')) ?>
|
||||
</div>
|
||||
@@ -25,8 +25,59 @@ $jsonPayload = json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNI
|
||||
$this->registerJs(<<<JS
|
||||
(function() {
|
||||
var payload = {$jsonPayload};
|
||||
|
||||
function triggerChange(element) {
|
||||
if (!element) {
|
||||
return;
|
||||
}
|
||||
|
||||
var event;
|
||||
if (typeof Event === 'function') {
|
||||
event = new Event('change', { bubbles: true });
|
||||
} else {
|
||||
event = document.createEvent('Event');
|
||||
event.initEvent('change', true, true);
|
||||
}
|
||||
element.dispatchEvent(event);
|
||||
}
|
||||
|
||||
function closeByFrameContext() {
|
||||
if (!window.parent || window.parent === window) {
|
||||
return;
|
||||
}
|
||||
|
||||
var frameElement = window.frameElement;
|
||||
if (!frameElement || !frameElement.parentElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
var closeControl = frameElement.parentElement.querySelector('.animal-tile-inline-iframe-close[for]');
|
||||
if (!closeControl) {
|
||||
return;
|
||||
}
|
||||
|
||||
var targetId = String(closeControl.getAttribute('for') || '');
|
||||
if (!targetId) {
|
||||
return;
|
||||
}
|
||||
|
||||
var targetElement = window.parent.document.getElementById(targetId);
|
||||
if (!targetElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((targetElement.type || '').toLowerCase() === 'radio') {
|
||||
targetElement.checked = true;
|
||||
} else {
|
||||
targetElement.checked = false;
|
||||
}
|
||||
|
||||
triggerChange(targetElement);
|
||||
}
|
||||
|
||||
if (window.parent && window.parent !== window) {
|
||||
window.parent.postMessage(payload, '*');
|
||||
closeByFrameContext();
|
||||
}
|
||||
})();
|
||||
JS
|
||||
|
||||
@@ -5,27 +5,205 @@ use humhub\modules\animal_management\models\forms\TransferRequestForm;
|
||||
use humhub\modules\space\models\Space;
|
||||
use humhub\widgets\Button;
|
||||
use yii\bootstrap\ActiveForm;
|
||||
use yii\helpers\Json;
|
||||
|
||||
/* @var Space $space */
|
||||
/* @var Animal $animal */
|
||||
/* @var TransferRequestForm $model */
|
||||
/* @var bool $isInline */
|
||||
/* @var string $returnTo */
|
||||
|
||||
$isInline = isset($isInline) ? (bool)$isInline : false;
|
||||
$showTopCancel = (string)Yii::$app->request->get('showTopCancel', '0') === '1';
|
||||
$returnTo = (string)($returnTo ?? 'view');
|
||||
$transferFormId = 'animal-transfer-request-form';
|
||||
|
||||
$this->registerCss(<<<CSS
|
||||
.animal-transfer-inline-shell.panel {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border: 1px solid rgba(255, 255, 255, 0.22);
|
||||
border-radius: 12px;
|
||||
background: rgba(10, 18, 28, 0.36);
|
||||
}
|
||||
|
||||
.animal-transfer-inline-shell > .panel-body {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
background: rgba(10, 18, 28, 0.2);
|
||||
}
|
||||
|
||||
.animal-transfer-inline-shell,
|
||||
.animal-transfer-inline-shell .panel-body,
|
||||
.animal-transfer-inline-shell .panel-heading,
|
||||
.animal-transfer-inline-shell .control-label,
|
||||
.animal-transfer-inline-shell .help-block {
|
||||
color: #eef5fb;
|
||||
}
|
||||
|
||||
.animal-transfer-inline-shell .panel-heading {
|
||||
background: rgba(15, 23, 42, 0.4);
|
||||
border-color: rgba(255, 255, 255, 0.22);
|
||||
margin-left: 20px;
|
||||
margin-bottom: 20px;
|
||||
padding: 10px 20px;
|
||||
max-width: fit-content;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.animal-transfer-inline-shell .panel-heading strong {
|
||||
color: #f8fafc;
|
||||
}
|
||||
|
||||
.animal-transfer-inline-shell .form-control {
|
||||
background: rgba(10, 18, 28, 0.56);
|
||||
border-color: rgba(255, 255, 255, 0.44);
|
||||
color: #f3f8ff;
|
||||
}
|
||||
|
||||
.animal-transfer-inline-shell .form-control::placeholder {
|
||||
color: rgba(243, 248, 255, 0.72);
|
||||
}
|
||||
|
||||
.animal-transfer-inline-shell select.form-control option {
|
||||
color: #0f1b2a;
|
||||
}
|
||||
|
||||
.animal-transfer-inline-shell .animal-inline-top-save-action {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
padding: 0;
|
||||
border-radius: 999px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.36);
|
||||
background: rgba(15, 23, 42, 0.72);
|
||||
color: #f8fafc;
|
||||
cursor: pointer;
|
||||
line-height: 1;
|
||||
font-size: 12px;
|
||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.28);
|
||||
}
|
||||
|
||||
.animal-transfer-inline-shell .animal-inline-top-save-action:hover,
|
||||
.animal-transfer-inline-shell .animal-inline-top-save-action:focus {
|
||||
background: rgba(30, 41, 59, 0.86);
|
||||
border-color: rgba(255, 255, 255, 0.5);
|
||||
color: #f8fafc;
|
||||
outline: none;
|
||||
}
|
||||
CSS
|
||||
);
|
||||
|
||||
if ($isInline) {
|
||||
$this->registerCss(<<<CSS
|
||||
html, body {
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
background: transparent !important;
|
||||
scrollbar-width: none;
|
||||
-ms-overflow-style: none;
|
||||
}
|
||||
|
||||
html::-webkit-scrollbar, body::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
body > .panel:first-child {
|
||||
margin-top: 0 !important;
|
||||
}
|
||||
CSS
|
||||
);
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel panel-default animal-transfer-inline-shell">
|
||||
<?php if ($isInline): ?>
|
||||
<div class="animal-inline-top-actions" style="display:flex;justify-content:flex-end;gap:8px;margin:8px 38px 6px 0;">
|
||||
<?= \yii\helpers\Html::submitButton('<i class="fa fa-check"></i>', [
|
||||
'class' => 'animal-inline-top-save-action',
|
||||
'title' => Yii::t('AnimalManagementModule.base', 'Send Request'),
|
||||
'form' => $transferFormId,
|
||||
]) ?>
|
||||
<?php if ($showTopCancel): ?>
|
||||
<?= \yii\helpers\Html::button('<i class="fa fa-times"></i>', [
|
||||
'id' => 'transfer-inline-add-cancel-icon',
|
||||
'class' => 'animal-inline-top-save-action',
|
||||
'title' => Yii::t('AnimalManagementModule.base', 'Cancel'),
|
||||
'type' => 'button',
|
||||
]) ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="panel-heading">
|
||||
<?= Yii::t('AnimalManagementModule.base', '<strong>Transfer Request</strong> for {animal}', ['animal' => $animal->getDisplayName()]) ?>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<?php $form = ActiveForm::begin(); ?>
|
||||
<?php
|
||||
$formOptions = ['id' => $transferFormId];
|
||||
if (!$isInline) {
|
||||
$formOptions['target'] = '_top';
|
||||
}
|
||||
$form = ActiveForm::begin(['options' => $formOptions]);
|
||||
?>
|
||||
|
||||
<?= \yii\helpers\Html::hiddenInput('returnTo', $returnTo) ?>
|
||||
|
||||
<?= $form->errorSummary($model, ['showAllErrors' => true]) ?>
|
||||
|
||||
<?= $form->field($model, 'to_space_id')->dropDownList($model->getTargetOptions(), ['prompt' => Yii::t('AnimalManagementModule.base', 'Select destination rescue')]) ?>
|
||||
<?= $form->field($model, 'request_message')->textarea(['rows' => 4]) ?>
|
||||
<?= $form->field($model, 'conditions_text')->textarea(['rows' => 3]) ?>
|
||||
|
||||
<?php if (!$isInline): ?>
|
||||
<?= Button::save(Yii::t('AnimalManagementModule.base', 'Send Request'))->submit() ?>
|
||||
<?= Button::asLink(Yii::t('AnimalManagementModule.base', 'Cancel'))
|
||||
->link($space->createUrl('/animal_management/animals/index')) ?>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php ActiveForm::end(); ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
if ($isInline) {
|
||||
$cancelPayload = Json::htmlEncode([
|
||||
'source' => 'animal-inline-editor',
|
||||
'type' => 'cancel',
|
||||
'collapseId' => 'transfer-add-inline',
|
||||
]);
|
||||
|
||||
$this->registerJs(<<<JS
|
||||
(function() {
|
||||
function postInlineCancel() {
|
||||
if (window.parent && window.parent !== window) {
|
||||
window.parent.postMessage($cancelPayload, '*');
|
||||
}
|
||||
}
|
||||
|
||||
if (window.jQuery) {
|
||||
window.jQuery(document).on('click', '#transfer-inline-add-cancel, #transfer-inline-add-cancel-icon', function() {
|
||||
postInlineCancel();
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('click', function(event) {
|
||||
var target = event.target;
|
||||
if (!target || !target.closest) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!target.closest('#transfer-inline-add-cancel, #transfer-inline-add-cancel-icon')) {
|
||||
return;
|
||||
}
|
||||
|
||||
postInlineCancel();
|
||||
}, false);
|
||||
})();
|
||||
JS
|
||||
, \yii\web\View::POS_END);
|
||||
}
|
||||
?>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -2,6 +2,7 @@
|
||||
|
||||
use humhub\modules\animal_management\models\forms\DisplaySettingsForm;
|
||||
use humhub\modules\animal_management\models\forms\FieldDefinitionSettingsForm;
|
||||
use humhub\modules\space\models\Space;
|
||||
use humhub\widgets\Button;
|
||||
use yii\bootstrap\ActiveForm;
|
||||
use yii\helpers\Html;
|
||||
@@ -10,6 +11,7 @@ use yii\helpers\Html;
|
||||
/* @var int $animalCount */
|
||||
/* @var FieldDefinitionSettingsForm $fieldSettingsForm */
|
||||
/* @var DisplaySettingsForm $displaySettingsForm */
|
||||
/* @var Space $space */
|
||||
?>
|
||||
|
||||
<div class="panel panel-default">
|
||||
@@ -20,6 +22,25 @@ use yii\helpers\Html;
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="panel-body">
|
||||
<div class="well well-sm" style="margin-bottom:14px;">
|
||||
<div style="font-weight:700;margin-bottom:6px;"><?= Yii::t('AnimalManagementModule.base', 'Module Setup') ?></div>
|
||||
<div style="margin-bottom:8px;">
|
||||
<?= Yii::t('AnimalManagementModule.base', 'Animal Management provides intake, profile tracking, medical/progress records, transfers, and related feed integrations for this rescue space.') ?>
|
||||
</div>
|
||||
<div style="margin-bottom:10px;">
|
||||
<?= Yii::t('AnimalManagementModule.base', 'Run setup to apply pending Animal Management migrations and initialize default module settings for this space.') ?>
|
||||
</div>
|
||||
<?= Html::a(
|
||||
Yii::t('AnimalManagementModule.base', 'Run Animal Management Setup'),
|
||||
$space->createUrl('/animal_management/settings/setup'),
|
||||
[
|
||||
'class' => 'btn btn-primary btn-sm',
|
||||
'data-method' => 'post',
|
||||
'data-confirm' => Yii::t('AnimalManagementModule.base', 'Run Animal Management setup now for this space?'),
|
||||
]
|
||||
) ?>
|
||||
</div>
|
||||
|
||||
<p><?= Yii::t('AnimalManagementModule.base', 'Configure intake/profile field definitions used by Animal Management.') ?></p>
|
||||
|
||||
<div class="well well-sm" style="margin-bottom:12px;">
|
||||
|
||||
@@ -7,15 +7,17 @@ use humhub\modules\animal_management\models\AnimalFieldValue;
|
||||
use humhub\modules\animal_management\models\AnimalGalleryItem;
|
||||
use humhub\modules\animal_management\models\AnimalMedicalVisit;
|
||||
use humhub\modules\animal_management\models\forms\DisplaySettingsForm;
|
||||
use humhub\modules\animal_management\permissions\ManageAnimals;
|
||||
use humhub\modules\content\components\ContentContainerActiveRecord;
|
||||
use humhub\modules\rescue_foundation\models\RescueFieldDefinition;
|
||||
use humhub\modules\space\models\Space;
|
||||
use Yii;
|
||||
use yii\base\Widget;
|
||||
|
||||
class SearchAnimalProfilesBlock extends Widget
|
||||
{
|
||||
public ContentContainerActiveRecord $contentContainer;
|
||||
public int $limit = 10;
|
||||
public int $limit = 4;
|
||||
|
||||
public function run()
|
||||
{
|
||||
@@ -25,29 +27,19 @@ class SearchAnimalProfilesBlock extends Widget
|
||||
. '</div>';
|
||||
}
|
||||
|
||||
$queryValue = trim((string)Yii::$app->request->get('q', ''));
|
||||
$showAll = ((int)Yii::$app->request->get('animalFeedAll', 0)) === 1;
|
||||
$countParam = (int)Yii::$app->request->get('animalFeedCount', $this->limit);
|
||||
if ($countParam < $this->limit) {
|
||||
$countParam = $this->limit;
|
||||
}
|
||||
if ($countParam > 200) {
|
||||
$countParam = 200;
|
||||
}
|
||||
|
||||
$query = Animal::find()->where(['contentcontainer_id' => $this->contentContainer->contentcontainer_id]);
|
||||
|
||||
if ($queryValue !== '') {
|
||||
$query->andWhere([
|
||||
'or',
|
||||
['like', 'animal_uid', $queryValue],
|
||||
['like', 'name', $queryValue],
|
||||
['like', 'species', $queryValue],
|
||||
]);
|
||||
$totalCount = (int)$query->count();
|
||||
$perPage = max(1, $this->limit);
|
||||
$page = (int)Yii::$app->request->get('animalFeedPage', 1);
|
||||
if ($page < 1) {
|
||||
$page = 1;
|
||||
}
|
||||
|
||||
$totalCount = (int)$query->count();
|
||||
$displayCount = $showAll ? $totalCount : min($countParam, $totalCount);
|
||||
$pageCount = max(1, (int)ceil($totalCount / $perPage));
|
||||
if ($page > $pageCount) {
|
||||
$page = $pageCount;
|
||||
}
|
||||
$offset = ($page - 1) * $perPage;
|
||||
|
||||
$settings = Yii::$app->getModule('animal_management')->settings->contentContainer($this->contentContainer);
|
||||
$heading = trim((string)$settings->get('searchBlockHeading', DisplaySettingsForm::DEFAULT_SEARCH_BLOCK_HEADING));
|
||||
@@ -60,7 +52,8 @@ class SearchAnimalProfilesBlock extends Widget
|
||||
|
||||
$animals = $query
|
||||
->orderBy(['updated_at' => SORT_DESC, 'id' => SORT_DESC])
|
||||
->limit($displayCount)
|
||||
->offset($offset)
|
||||
->limit($perPage)
|
||||
->all();
|
||||
|
||||
$animalIds = array_map(static function (Animal $animal): int {
|
||||
@@ -70,9 +63,14 @@ class SearchAnimalProfilesBlock extends Widget
|
||||
$latestMedicalVisitByAnimal = $this->resolveLatestMedicalVisits($animalIds);
|
||||
$animalImageUrls = $this->resolveAnimalImageUrls($animalIds, ['profile_image_url', 'profile_image', 'photo_url', 'image_url', 'photo'], false);
|
||||
$tileFieldOverrides = $this->resolveDisplayFieldOverrides($animalIds, 'tile_display_fields');
|
||||
$animalDonationGoalsByAnimal = $this->resolveAnimalDonationGoals($animalIds);
|
||||
|
||||
$hasMore = !$showAll && $displayCount < $totalCount;
|
||||
$nextCount = min($displayCount + $this->limit, $totalCount);
|
||||
$canManageAnimals = $this->contentContainer->can(ManageAnimals::class)
|
||||
|| ($this->contentContainer instanceof Space && $this->contentContainer->isAdmin());
|
||||
$showDonationSettingsButton = $canManageAnimals && $this->contentContainer->moduleManager->isEnabled('donations');
|
||||
|
||||
$hasPreviousPage = $page > 1;
|
||||
$hasNextPage = $page < $pageCount;
|
||||
|
||||
$viewFile = $this->getViewPath() . '/searchAnimalProfilesBlock.php';
|
||||
if (!is_file($viewFile)) {
|
||||
@@ -84,20 +82,59 @@ class SearchAnimalProfilesBlock extends Widget
|
||||
return $this->render('searchAnimalProfilesBlock', [
|
||||
'animals' => $animals,
|
||||
'contentContainer' => $this->contentContainer,
|
||||
'queryValue' => $queryValue,
|
||||
'heading' => $heading,
|
||||
'tileFields' => $tileFields,
|
||||
'tileFieldOverrides' => $tileFieldOverrides,
|
||||
'latestMedicalVisitByAnimal' => $latestMedicalVisitByAnimal,
|
||||
'animalImageUrls' => $animalImageUrls,
|
||||
'animalDonationGoalsByAnimal' => $animalDonationGoalsByAnimal,
|
||||
'showDonationSettingsButton' => $showDonationSettingsButton,
|
||||
'totalCount' => $totalCount,
|
||||
'displayCount' => $displayCount,
|
||||
'hasMore' => $hasMore,
|
||||
'nextCount' => $nextCount,
|
||||
'showAll' => $showAll,
|
||||
'page' => $page,
|
||||
'pageCount' => $pageCount,
|
||||
'hasPreviousPage' => $hasPreviousPage,
|
||||
'hasNextPage' => $hasNextPage,
|
||||
]);
|
||||
}
|
||||
|
||||
private function resolveAnimalDonationGoals(array $animalIds): array
|
||||
{
|
||||
$animalIds = array_values(array_unique(array_map('intval', $animalIds)));
|
||||
if (empty($animalIds)
|
||||
|| !$this->contentContainer->moduleManager->isEnabled('donations')
|
||||
) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$donationGoalClass = 'humhub\\modules\\donations\\models\\DonationGoal';
|
||||
if (!class_exists($donationGoalClass)
|
||||
|| Yii::$app->db->schema->getTableSchema($donationGoalClass::tableName(), true) === null
|
||||
) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$goals = $donationGoalClass::find()
|
||||
->where([
|
||||
'contentcontainer_id' => $this->contentContainer->contentcontainer_id,
|
||||
'goal_type' => $donationGoalClass::TYPE_ANIMAL,
|
||||
])
|
||||
->andWhere(['target_animal_id' => $animalIds])
|
||||
->orderBy(['is_active' => SORT_DESC, 'id' => SORT_DESC])
|
||||
->all();
|
||||
|
||||
$result = [];
|
||||
foreach ($goals as $goal) {
|
||||
$animalId = (int)$goal->target_animal_id;
|
||||
if ($animalId <= 0 || isset($result[$animalId])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$result[$animalId] = $goal;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function normalizeDisplayFields($raw, array $default): array
|
||||
{
|
||||
if (is_string($raw)) {
|
||||
|
||||
@@ -7,46 +7,30 @@ use yii\helpers\Html;
|
||||
|
||||
/* @var Animal[] $animals */
|
||||
/* @var ContentContainerActiveRecord $contentContainer */
|
||||
/* @var string $queryValue */
|
||||
/* @var string $heading */
|
||||
/* @var array $tileFields */
|
||||
/* @var array<int, array> $tileFieldOverrides */
|
||||
/* @var array<int, AnimalMedicalVisit> $latestMedicalVisitByAnimal */
|
||||
/* @var array<int, string> $animalImageUrls */
|
||||
/* @var array<int, mixed> $animalDonationGoalsByAnimal */
|
||||
/* @var bool $showDonationSettingsButton */
|
||||
/* @var int $totalCount */
|
||||
/* @var int $displayCount */
|
||||
/* @var bool $hasMore */
|
||||
/* @var int $nextCount */
|
||||
/* @var bool $showAll */
|
||||
/* @var int $page */
|
||||
/* @var int $pageCount */
|
||||
/* @var bool $hasPreviousPage */
|
||||
/* @var bool $hasNextPage */
|
||||
|
||||
$moduleEnabled = $contentContainer->moduleManager->isEnabled('animal_management');
|
||||
$allAnimalsUrl = $contentContainer->createUrl('/animal_management/animals/index');
|
||||
$currentParams = Yii::$app->request->getQueryParams();
|
||||
$buildProfileUrl = static function (array $overrides) use ($contentContainer, $currentParams): string {
|
||||
unset($currentParams['q'], $currentParams['animalFeedCount'], $currentParams['animalFeedAll']);
|
||||
$params = array_merge($currentParams, $overrides);
|
||||
return $contentContainer->createUrl('/space_profiles/profile/view', $params);
|
||||
};
|
||||
?>
|
||||
|
||||
<h4 style="margin-top:0;"><?= Html::encode($heading) ?></h4>
|
||||
|
||||
<?php if ($moduleEnabled): ?>
|
||||
<form method="get" action="<?= Html::encode($contentContainer->createUrl('/space_profiles/profile/view')) ?>" style="margin-bottom:12px;">
|
||||
<div class="input-group">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
name="q"
|
||||
value="<?= Html::encode($queryValue) ?>"
|
||||
placeholder="<?= Html::encode(Yii::t('AnimalManagementModule.base', 'Search by name, species, or ID')) ?>"
|
||||
>
|
||||
<input type="hidden" name="animalFeedCount" value="10">
|
||||
<input type="hidden" name="animalFeedAll" value="0">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default" type="submit"><?= Yii::t('AnimalManagementModule.base', 'Search') ?></button>
|
||||
</span>
|
||||
</div>
|
||||
</form>
|
||||
<?php else: ?>
|
||||
<?php if (!$moduleEnabled): ?>
|
||||
<div class="well well-sm" style="margin-bottom:12px;">
|
||||
<?= Yii::t('AnimalManagementModule.base', 'Animal profiles are not enabled for this rescue.') ?>
|
||||
</div>
|
||||
@@ -68,28 +52,36 @@ $buildProfileUrl = static function (array $overrides) use ($contentContainer, $c
|
||||
'imageUrl' => $animalImageUrls[$animalId] ?? '',
|
||||
'tileFields' => $tileFieldOverrides[$animalId] ?? $tileFields,
|
||||
'showMedicalIcon' => true,
|
||||
'showDonationSettingsButton' => $showDonationSettingsButton,
|
||||
'existingDonationGoal' => $animalDonationGoalsByAnimal[$animalId] ?? null,
|
||||
'tileLayoutMode' => 'rows',
|
||||
]) ?>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($moduleEnabled): ?>
|
||||
<div style="display:flex;gap:8px;align-items:center;flex-wrap:wrap;">
|
||||
<?php if ($hasMore): ?>
|
||||
<a class="btn btn-default btn-sm" href="<?= Html::encode($buildProfileUrl(['animalFeedCount' => $nextCount, 'animalFeedAll' => 0])) ?>">
|
||||
<?= Yii::t('AnimalManagementModule.base', 'Show More') ?>
|
||||
<?php if ($moduleEnabled && $totalCount > 0): ?>
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;gap:8px;flex-wrap:wrap;">
|
||||
<div class="text-muted" style="font-size:12px;">
|
||||
<?= Yii::t('AnimalManagementModule.base', 'Page {page} of {pages}', ['page' => $page, 'pages' => $pageCount]) ?>
|
||||
</div>
|
||||
<div style="display:flex;align-items:center;gap:8px;">
|
||||
<?php if ($hasPreviousPage): ?>
|
||||
<a class="btn btn-default btn-sm" href="<?= Html::encode($buildProfileUrl(['animalFeedPage' => $page - 1])) ?>">
|
||||
<?= Yii::t('AnimalManagementModule.base', 'Previous') ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<?php if (!$showAll && $totalCount > 0): ?>
|
||||
<a class="btn btn-default btn-sm" href="<?= Html::encode($buildProfileUrl(['animalFeedAll' => 1])) ?>">
|
||||
<?= Yii::t('AnimalManagementModule.base', 'Show All') ?>
|
||||
<?php if ($hasNextPage): ?>
|
||||
<a class="btn btn-default btn-sm" href="<?= Html::encode($buildProfileUrl(['animalFeedPage' => $page + 1])) ?>">
|
||||
<?= Yii::t('AnimalManagementModule.base', 'Next') ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<?php if ($totalCount > 0): ?>
|
||||
<span class="text-muted" style="font-size:12px;">
|
||||
<?= Yii::t('AnimalManagementModule.base', '{shown} of {total} shown', ['shown' => $displayCount, 'total' => $totalCount]) ?>
|
||||
</span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top:10px;text-align:center;">
|
||||
<a href="<?= Html::encode($allAnimalsUrl) ?>" style="font-weight:700;text-decoration:underline;">
|
||||
<?= Yii::t('AnimalManagementModule.base', 'All Animals') ?>
|
||||
</a>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
Reference in New Issue
Block a user