diff --git a/backend/services/memberService.js b/backend/services/memberService.js index 8ca1c9e..d620946 100644 --- a/backend/services/memberService.js +++ b/backend/services/memberService.js @@ -82,8 +82,8 @@ class MemberService { return results; } catch (error) { - console.error('[getClubMembers] - Error:', error); - throw error; + console.error('[getClubMembers] - Error:', error); + throw error; } } @@ -624,7 +624,7 @@ class MemberService { if (!member) { return { status: 404, response: { success: false, error: 'Member not found in this club' } }; } - + await this._migrateLegacyImage(memberId); const imageRecord = await MemberImage.findOne({ @@ -634,7 +634,7 @@ class MemberService { if (!imageRecord) { return { status: 404, response: { success: false, error: 'Image not found' } }; } - + const imagePath = path.join('images', 'members', String(memberId), imageRecord.fileName); if (!fs.existsSync(imagePath)) { return { status: 404, response: { success: false, error: 'Image file not found on disk' } }; @@ -642,23 +642,23 @@ class MemberService { const imageBuffer = await fs.promises.readFile(imagePath); const rotationAngle = direction === 'left' ? -90 : 90; - + const rotatedBuffer = await sharp(imageBuffer) .rotate(rotationAngle) .jpeg({ quality: 80 }) .toBuffer(); - + await fs.promises.writeFile(imagePath, rotatedBuffer); await imageRecord.update({ updatedAt: new Date() }); const imageData = await this._prepareMemberImages(member, { forceReload: true }); const updatedImage = imageData.images.find(img => img.id === imageRecord.id) || null; - - return { - status: 200, - response: { - success: true, + + return { + status: 200, + response: { + success: true, message: `Bild um ${rotationAngle}° gedreht`, direction, rotation: rotationAngle, @@ -666,7 +666,7 @@ class MemberService { images: imageData.images, primaryImageId: imageData.primaryImageId, primaryImageUrl: imageData.primaryImageUrl - } + } }; } catch (error) { console.error('[rotateMemberImage] - Error:', error); @@ -1136,8 +1136,14 @@ class MemberService { const maxColumns = Math.max(1, Math.floor((1920 - galleryGap) / (tileDimension + galleryGap))); const columns = Math.min(maxColumns, galleryEntries.length); const rows = Math.ceil(galleryEntries.length / columns); - const canvasWidth = galleryGap + columns * (tileDimension + galleryGap) - galleryGap; - const canvasHeight = galleryGap + rows * (tileDimension + galleryGap) - galleryGap; + const canvasWidth = Math.max( + 1, + galleryGap + columns * (tileDimension + galleryGap) + ); + const canvasHeight = Math.max( + 1, + galleryGap + rows * (tileDimension + galleryGap) + ); const gap = galleryGap; const backgroundColor = '#101010'; const grid = this._computeGalleryGrid(galleryEntries.length, canvasWidth, canvasHeight, gap); @@ -1147,8 +1153,8 @@ class MemberService { for (const entry of galleryEntries) { const row = Math.floor(index / grid.columns); const col = index % grid.columns; - const left = gap + col * (grid.tileWidth + gap); - const top = gap + row * (grid.tileHeight + gap); + const left = galleryGap + col * (grid.tileWidth + galleryGap); + const top = galleryGap + row * (grid.tileHeight + galleryGap); const resizedBuffer = await sharp(entry.filePath) .resize(200, 200, { fit: 'cover' }) @@ -1218,9 +1224,13 @@ class MemberService { } _computeGalleryGrid(count, canvasWidth, canvasHeight, gap) { - let best = null; - const tileDimension = 200; + let best = { + columns: 1, + rows: count, + tileWidth: tileDimension, + tileHeight: tileDimension + }; for (let columns = 1; columns <= count; columns += 1) { const rows = Math.ceil(count / columns); @@ -1236,25 +1246,16 @@ class MemberService { continue; } - if (!best) { + if (columns > best.columns || (columns === best.columns && rows < best.rows)) { best = { columns, rows, tileWidth, - tileHeight, + tileHeight }; } } - if (!best) { - best = { - columns: 1, - rows: count, - tileWidth: tileDimension, - tileHeight: tileDimension - }; - } - return best; } diff --git a/frontend/src/views/DiaryView.vue b/frontend/src/views/DiaryView.vue index 68feca8..32296be 100644 --- a/frontend/src/views/DiaryView.vue +++ b/frontend/src/views/DiaryView.vue @@ -2474,20 +2474,23 @@ h3 { .gallery-dialog-content { display: flex; - justify-content: center; - align-items: center; + justify-content: flex-start; + align-items: flex-start; + padding: 20px; min-height: 60vh; max-height: 70vh; + overflow: auto; } .gallery-image-wrapper { - max-width: 100%; - max-height: 100%; + max-width: none; + max-height: none; } .gallery-dialog-image { + display: block; max-width: 100%; - max-height: 100%; + height: auto; border-radius: 8px; box-shadow: 0 4px 18px rgba(0, 0, 0, 0.35); }