Commit graph

10 commits

Author SHA1 Message Date
Paulo Castellano
44127c4890 Remove the Vitest frontend unit-test layer
The project's test strategy is backend + e2e only, so drop the Vitest setup that had been added for the crop math: the imageCrop.test.ts suite, vitest.config.ts, the dependency and test:unit script, the CI step, and the test:all reference. The crop math is exercised through the Pest browser test.
2026-07-04 10:53:08 -03:00
Paulo Castellano
ef81ea74a8 Add frontend unit tests and harden the cropper's test coverage
Add Vitest (test:unit) with exact-value tests for the crop math (containScale, defaultSelection, clampSelection, all resizeSelection corners, and mime/filename resolution), and wire it plus the Pest browser test into CI. The browser test now samples output pixels against a four-quadrant fixture, so it detects a blank, flipped, or wrong crop rather than only asserting a 512x512 canvas. Add composer test:all to run PHP + Vitest + browser tests locally.
2026-07-04 09:56:38 -03:00
Paulo Castellano
36ccc570e0 Rewrite the image cropper as a movable/resizable selection box
Replace the move-image-behind-a-fixed-frame model with a selection box over the fully visible (contain-fit) image: drag to move, corner handles to resize, locked to 1:1 for the square avatar/logo output. The default selection is inset so the crop outline is always visible, handles sit inside the frame so they are never clipped, and wheel/pinch zoom is swallowed. Reset drag state on open/close, guard pointer capture and multi-touch, and fail-safe the canvas encode. Update the crop copy in all 15 locales to match the selection model.
2026-07-04 09:56:31 -03:00
Paulo Castellano
2549a82e9b Address review: cropper mime/zoom/error fixes, harden browser test
- Output a canvas-encodable mime (jpeg/png/webp, else png) and keep the File's
  name/extension in sync, so non-encodable input (gif/svg/heic) no longer ships
  PNG bytes mislabeled as the original type.
- Clamp zoom to a maximum (8x cover) so scrolling in can't collapse the crop to
  a sub-pixel region.
- Handle undecodable/zero-dimension images (@error + naturalWidth guard) with a
  crop_error message instead of a permanently-disabled Save.
- Replace the str_contains(static::class) Vite heuristic with a dedicated
  BrowserTestCase ($fakesVite = false).
- The browser test now decodes the dispatched blob and asserts a 512x512 image,
  and uses route(..., absolute: false) instead of a hardcoded path.
- Remove tests/Browser/ProbeTest.php (committed debug scratch).
2026-07-03 22:07:23 -03:00
Paulo Castellano
c6369a6ddb Crop the avatar/logo before upload with a dependency-free cropper
Selecting an avatar or workspace logo now opens a crop dialog (drag + zoom)
before uploading, so the image is framed the way it renders. The crop is
performed client-side and the resized 512x512 result is what gets uploaded.

This reworks the idea from #131 without its cropper dependency: vue-advanced-cropper
was last released ~2 years ago and we did not want an unmaintained package for
something this load-bearing. What we need is narrow (fixed 1:1, a circle/square
mask, fixed-size output), so a small canvas-based cropper covers it:

- imageCrop.ts: pure transform math (cover-fit, clamp, zoom, viewport->source).
- ImageCropperDialog.vue: CSS-transform preview, pointer drag, wheel/button zoom,
  a ResizeObserver to measure the modal (no requestAnimationFrame timing hacks),
  and a canvas toBlob only on save.
- PhotoUpload.vue: opens the cropper on file select; the mask shape follows the
  display shape (round avatar / square logo) instead of always being round.
- crop_* strings added to all 15 locales.

Also installs Pest browser testing (pest-plugin-browser + Playwright) and adds a
browser test for the crop flow. TestCase only calls withoutVite() for non-browser
tests, since browser tests need the real Vite assets to boot the SPA. The Pest
browser server does not parse multipart uploads, so the test asserts the crop
dispatches the correct upload request; endpoint persistence stays covered by
ProfileUpdateTest.
2026-07-03 21:46:19 -03:00
Paulo Castellano
a8bed34d17 refactor(media): centralize frontend media-type detection in lib/mediaType
Mirror the backend App\Enums\Media\Type on the frontend so "is this an
image/video/PDF?" has a single definition instead of being hand-written
(type === 'x' || mime_type startsWith ...) across a dozen files.

- add lib/mediaType.ts: MediaType union, classify(), fromMimeType(),
  fromExtension(), isImage/isVideo/isDocument/isGif, acceptAttribute()
- route every MediaItem detection and every File-upload validator through it
- fix MediaDropzone rendering a typeless image item (AI/Unsplash/Giphy)
  as a broken <video> via the img-vs-video v-else
- collapse getMediaIncompatibilityReason onto the shared
  getMediaValidationWarning core (canSchedule / variant selection unchanged)
- tighten MediaItem/AssetMedia/SavedMedia/PickedMedia .type to MediaType
- replace GalleryBrowser's hardcoded accept list with acceptAttribute()
2026-06-25 18:19:58 -03:00
Paulo Castellano
9a692b4608 Enhance automation functionality: Introduce workflow variables and improve node validation
- Added support for workflow variables in automations, allowing users to define reusable values.
- Implemented validation for Generate nodes to ensure intended image counts align with selected accounts.
- Updated automation models and requests to handle new variables, including encryption for sensitive data.
- Enhanced UI to display variables and their management within the automation editor.
- Improved error handling for webhook and HTTP nodes to prevent requests to invalid URLs.
- Refactored various components for better context resolution during automation runs.
2026-06-11 15:47:29 -03:00
Paulo Castellano
34272a573f feat: implement consolidated authentication settings including session management and social provider integration 2026-05-03 17:42:44 -03:00
Paulo Castellano
f3f72afecd refactor: auth split layout, subscribe redesign, onboarding, i18n, cookie locale
Auth pages:
- Create AuthSplitLayout with animated feature slides (6 slides, 3 languages)
- All auth pages use split layout (form left, visual right)
- Add show/hide password toggle with tooltip on Register
- Legal footer only shown on Register via showLegal prop

Subscribe page:
- Redesign to match auth card pattern (centered, clean)
- Platform icons, feature checklist, dynamic trial days (trialDays - 1)
- Add "Switch workspace" link
- Full i18n (en, es, pt-BR)

Onboarding:
- Rename URLs: step1 -> role, step2 -> connect
- Add enforceStep() to prevent skipping/going back steps
- Redirect /onboarding to /onboarding/role
- Redesign Step2 with AuthSplitLayout and compact platform list
- 21 tests covering all step enforcement scenarios

Workspaces page:
- Redesign with AuthSplitLayout (list with avatars, current badge)

Language system:
- Move locale from DB to cookie (forever, unencrypted, session.domain)
- Create SetLocale middleware (sets cookie if missing, validates against config)
- Rename lang/pt-br to lang/pt-BR
- Add dayjs es locale

Other:
- Copy utils.ts from sendkit (formatNumber, formatMoney, copyToClipboard)
- ConfirmDeleteModal with text confirmation (sendkit pattern)
- i18n for ConfirmDeleteModal internal strings (common.php)
- EmptyState component for posts index
- Exact match for "All" posts in sidebar
- Posts breadcrumbs show current status filter
- DialogFooter buttons aligned left
- API Keys page redesign with Table, DropdownMenu, EmptyState
- Extract CreateApiKeyDialog and InviteMemberDialog to components
- Remove API Keys from sidebar
- DropdownMenuItem destructive variant for Remove action
2026-03-30 11:53:42 -03:00
Paulo Castellano
6890147aa6 chore: first commit 2026-01-14 22:13:44 -03:00