├── public
├── favicon.ico
├── robots.txt
├── vendor
│ └── telescope
│ │ ├── favicon.ico
│ │ └── mix-manifest.json
└── .htaccess
├── database
├── .gitignore
├── seeders
│ ├── ClientSeeder.php
│ ├── ClientCompanySeeder.php
│ ├── RoleSeeder.php
│ ├── LabelSeeder.php
│ ├── TaskGroupSeeder.php
│ ├── ProjectSeeder.php
│ ├── OwnerCompanySeeder.php
│ └── DatabaseSeeder.php
├── factories
│ ├── ClientFactory.php
│ ├── UserFactory.php
│ └── ClientCompanyFactory.php
└── migrations
│ ├── 2025_12_15_090401_add_color_to_task_groups_table.php
│ ├── 2023_11_03_134217_create_countries_table.php
│ ├── 2023_11_15_220141_create_subscribe_task.php
│ ├── 2023_11_10_144123_create_label_task_pivot_table.php
│ ├── 2023_11_01_182514_add_archived_at_to_roles.php
│ ├── 2023_11_06_153749_create_project_user_access.php
│ ├── 2024_01_30_190158_add_rate_to_projects.php
│ ├── 2025_03_31_204815_add_fixed_price_to_tasks.php
│ ├── 2023_11_01_120111_create_labels_table.php
│ ├── 2014_10_12_100000_create_password_reset_tokens_table.php
│ ├── 2023_11_18_193550_create_comments_table.php
│ ├── 2023_11_02_165827_create_currencies_table.php
│ ├── 2023_11_07_131704_create_task_groups_table.php
│ ├── 2025_03_31_210544_add_pricing_type_to_tasks.php
│ ├── 2025_03_31_193719_add_default_pricing_type_to_projects.php
│ ├── 2018_12_14_000000_create_favorites_table.php
│ ├── 2023_11_16_144304_create_notifications_table.php
│ ├── 2023_11_04_104543_create_client_company_pivot_table.php
│ ├── 2023_10_31_113749_create_failed_jobs_table.php
│ ├── 2023_10_31_105255_create_jobs_table.php
│ ├── 2023_11_06_094257_create_projects_table.php
│ ├── 2023_11_15_220222_create_attachments.php
│ ├── 2023_11_28_155542_create_activities.php
│ ├── 2023_11_17_211110_create_time_logs_table.php
│ ├── 2019_12_14_000001_create_personal_access_tokens_table.php
│ └── 2014_10_12_000000_create_users_table.php
├── bootstrap
└── cache
│ └── .gitignore
├── storage
├── logs
│ └── .gitignore
├── app
│ ├── .gitignore
│ └── public
│ │ ├── avatars
│ │ └── .gitignore
│ │ └── .gitignore
└── framework
│ ├── testing
│ └── .gitignore
│ ├── views
│ └── .gitignore
│ ├── cache
│ ├── data
│ │ └── .gitignore
│ └── .gitignore
│ ├── sessions
│ └── .gitignore
│ └── .gitignore
├── pint.json
├── resources
├── views
│ ├── vendor
│ │ └── mail
│ │ │ ├── text
│ │ │ ├── footer.blade.php
│ │ │ ├── panel.blade.php
│ │ │ ├── subcopy.blade.php
│ │ │ ├── table.blade.php
│ │ │ ├── button.blade.php
│ │ │ ├── header.blade.php
│ │ │ ├── layout.blade.php
│ │ │ └── message.blade.php
│ │ │ └── html
│ │ │ ├── table.blade.php
│ │ │ ├── header.blade.php
│ │ │ ├── subcopy.blade.php
│ │ │ ├── footer.blade.php
│ │ │ ├── panel.blade.php
│ │ │ ├── message.blade.php
│ │ │ └── button.blade.php
│ └── app.blade.php
├── docs
│ ├── banner.jpg
│ ├── banner.afphoto
│ └── screenshots
│ │ ├── Task - dark.jpeg
│ │ ├── Invoice - dark.jpeg
│ │ ├── Task - light.jpeg
│ │ ├── Activity - dark.jpeg
│ │ ├── Activity - light.jpeg
│ │ ├── Dashboard - dark.jpeg
│ │ ├── Invoice - light.jpeg
│ │ ├── My tasks - dark.jpeg
│ │ ├── My tasks - light.jpeg
│ │ ├── Projects - dark.jpeg
│ │ ├── Projects - light.jpeg
│ │ ├── Dashboard - light.jpeg
│ │ ├── Project tasks - dark.jpeg
│ │ └── Project tasks - light.jpeg
├── js
│ ├── components
│ │ ├── css
│ │ │ ├── Notification.module.css
│ │ │ ├── RichTextEditor.module.css
│ │ │ ├── UserInfoCard.module.css
│ │ │ ├── Card.module.css
│ │ │ ├── TableHeader.module.css
│ │ │ └── FlashNotification.module.css
│ │ ├── ActionButton.jsx
│ │ ├── RoleBadge.jsx
│ │ ├── Card.jsx
│ │ ├── TableRowEmpty.jsx
│ │ ├── Label.jsx
│ │ ├── BackButton.jsx
│ │ ├── TaskGroupLabel.jsx
│ │ ├── Logo.jsx
│ │ ├── EmptyResult.jsx
│ │ ├── EmptyWithIcon.jsx
│ │ ├── Pagination.jsx
│ │ ├── Notification.jsx
│ │ ├── ClearFiltersButton.jsx
│ │ ├── ConfirmModal.jsx
│ │ ├── TableHead.jsx
│ │ ├── ArchivedFilterButton.jsx
│ │ ├── ImageModal.jsx
│ │ └── RichTextEditor
│ │ │ └── Mention
│ │ │ └── css
│ │ │ └── MentionList.css
│ ├── utils
│ │ ├── enums.js
│ │ ├── task.js
│ │ ├── domEvents.js
│ │ ├── axios.js
│ │ ├── currency.js
│ │ ├── table.js
│ │ ├── datetime.js
│ │ ├── user.js
│ │ ├── reorder.js
│ │ └── timer.js
│ ├── layouts
│ │ ├── css
│ │ │ ├── ContainerBox.module.css
│ │ │ ├── UserButton.module.css
│ │ │ └── Notifications.module.css
│ │ ├── ContainerBox.jsx
│ │ └── GuestLayout.jsx
│ ├── pages
│ │ ├── Auth
│ │ │ ├── css
│ │ │ │ ├── Login.module.css
│ │ │ │ ├── ForgotPassword.module.css
│ │ │ │ └── ResetPassword.module.css
│ │ │ └── LoginNotification.jsx
│ │ ├── Dashboard
│ │ │ ├── Cards
│ │ │ │ └── css
│ │ │ │ │ ├── ProjectCard.module.css
│ │ │ │ │ ├── OverdueTasks.module.css
│ │ │ │ │ ├── RecentlyAssignedTasks.module.css
│ │ │ │ │ └── RecentComments.module.css
│ │ │ └── css
│ │ │ │ └── Index.module.css
│ │ ├── Projects
│ │ │ ├── Index
│ │ │ │ ├── css
│ │ │ │ │ ├── FavoriteToggle.module.css
│ │ │ │ │ └── ProjectCard.module.css
│ │ │ │ └── FavoriteToggle.jsx
│ │ │ └── Tasks
│ │ │ │ ├── Drawers
│ │ │ │ └── css
│ │ │ │ │ ├── Comments.module.css
│ │ │ │ │ └── TaskDrawer.module.css
│ │ │ │ ├── Index
│ │ │ │ ├── Filters
│ │ │ │ │ ├── css
│ │ │ │ │ │ └── FilterButton.module.css
│ │ │ │ │ └── FilterButton.jsx
│ │ │ │ ├── Task.jsx
│ │ │ │ ├── Archive
│ │ │ │ │ ├── ArchivedTaskGroup.jsx
│ │ │ │ │ └── ArchivedItems.jsx
│ │ │ │ ├── FiltersDrawer.jsx
│ │ │ │ └── Task
│ │ │ │ │ └── css
│ │ │ │ │ └── TaskCard.module.css
│ │ │ │ └── css
│ │ │ │ └── Index.module.css
│ │ ├── MyWork
│ │ │ └── Tasks
│ │ │ │ └── css
│ │ │ │ ├── Index.module.css
│ │ │ │ └── Task.module.css
│ │ ├── Account
│ │ │ └── Notifications
│ │ │ │ └── css
│ │ │ │ └── Index.module.css
│ │ ├── Invoices
│ │ │ └── css
│ │ │ │ └── Task.module.css
│ │ └── css
│ │ │ └── Error.module.css
│ ├── types.ts
│ └── hooks
│ │ ├── usePreferences.js
│ │ ├── useAuthorization.js
│ │ ├── useSorting.js
│ │ ├── useRoles.js
│ │ ├── useImageLoader.js
│ │ ├── store
│ │ ├── useTaskGroupsStore.js
│ │ ├── tasks
│ │ │ └── TaskCommentsSlice.js
│ │ ├── taskGroups
│ │ │ └── TaskGroupWebSocketUpdatesSlice.js
│ │ └── useTaskDrawerStore.js
│ │ └── useForm.js
└── css
│ └── app.css
├── tests
├── Unit
│ └── ExampleTest.php
├── Feature
│ └── ExampleTest.php
├── TestCase.php
└── CreatesApplication.php
├── app
├── Enums
│ ├── Queue.php
│ ├── PricingType.php
│ └── Invoice.php
├── Models
│ ├── Permission.php
│ ├── Country.php
│ ├── Filters
│ │ ├── IsNullFilter.php
│ │ ├── WhereInFilter.php
│ │ ├── TaskOverdueFilter.php
│ │ ├── TaskCompletedFilter.php
│ │ └── WhereHasFilter.php
│ ├── Label.php
│ ├── Role.php
│ ├── Attachment.php
│ ├── TimeLog.php
│ ├── Comment.php
│ ├── Currency.php
│ └── Activity.php
├── Http
│ ├── Controllers
│ │ ├── Controller.php
│ │ ├── Account
│ │ │ ├── ProfileController.php
│ │ │ └── NotificationController.php
│ │ ├── Auth
│ │ │ └── AuthenticationController.php
│ │ ├── Task
│ │ │ ├── AttachmentController.php
│ │ │ └── CommentController.php
│ │ ├── Settings
│ │ │ └── OwnerCompanyController.php
│ │ ├── Invoice
│ │ │ └── InvoiceTasksController.php
│ │ └── DropdownValuesController.php
│ ├── Middleware
│ │ ├── EncryptCookies.php
│ │ ├── VerifyCsrfToken.php
│ │ ├── PreventRequestsDuringMaintenance.php
│ │ ├── TrimStrings.php
│ │ ├── TrustHosts.php
│ │ ├── Authenticate.php
│ │ ├── ValidateSignature.php
│ │ ├── TrustProxies.php
│ │ └── RedirectIfAuthenticated.php
│ ├── Resources
│ │ ├── Label
│ │ │ └── LabelResource.php
│ │ ├── Role
│ │ │ └── RoleResource.php
│ │ ├── Client
│ │ │ └── ClientResource.php
│ │ ├── User
│ │ │ ├── AuthUserResource.php
│ │ │ └── UserResource.php
│ │ ├── Notification
│ │ │ ├── NotificationResource.php
│ │ │ └── NotificationGroupedByDateCollection.php
│ │ ├── Project
│ │ │ └── ProjectResource.php
│ │ ├── Invoice
│ │ │ └── InvoiceResource.php
│ │ ├── Activity
│ │ │ └── ActivityGroupedByDateCollection.php
│ │ └── ClientCompany
│ │ │ └── ClientCompanyResource.php
│ └── Requests
│ │ ├── Comment
│ │ └── StoreCommentRequest.php
│ │ ├── TimeLog
│ │ └── StoreTimeLogRequest.php
│ │ ├── Label
│ │ ├── StoreLabelRequest.php
│ │ └── UpdateLabelRequest.php
│ │ ├── Role
│ │ ├── StoreRoleRequest.php
│ │ └── UpdateRoleRequest.php
│ │ ├── OwnerCompany
│ │ └── UpdateOwnerCompanyRequest.php
│ │ ├── Client
│ │ ├── StoreClientRequest.php
│ │ └── UpdateClientRequest.php
│ │ ├── User
│ │ ├── UpdateAuthUserRequest.php
│ │ ├── StoreUserRequest.php
│ │ └── UpdateUserRequest.php
│ │ ├── Project
│ │ ├── StoreProjectRequest.php
│ │ └── UpdateProjectRequest.php
│ │ └── TaskGroup
│ │ ├── StoreTaskGroupRequest.php
│ │ └── UpdateTaskGroupRequest.php
├── Events
│ ├── UserCreated.php
│ ├── Task
│ │ ├── TaskDeleted.php
│ │ ├── TaskCreated.php
│ │ ├── TaskOrderChanged.php
│ │ ├── AttachmentsUploaded.php
│ │ ├── CommentCreated.php
│ │ ├── TaskGroupChanged.php
│ │ ├── TimeLogDeleted.php
│ │ ├── AttachmentDeleted.php
│ │ ├── TaskRestored.php
│ │ └── TimeLogCreated.php
│ └── TaskGroup
│ │ ├── TaskGroupDeleted.php
│ │ ├── TaskGroupRestored.php
│ │ ├── TaskGroupUpdated.php
│ │ ├── TaskGroupOrderChanged.php
│ │ └── TaskGroupCreated.php
├── Actions
│ ├── ClientCompany
│ │ ├── UpdateClientCompany.php
│ │ └── CreateClientCompany.php
│ ├── OwnerCompany
│ │ └── UpdateOwnerCompany.php
│ ├── User
│ │ ├── UpdateAuthUser.php
│ │ ├── UpdateUser.php
│ │ └── CreateUser.php
│ └── Client
│ │ ├── UpdateClient.php
│ │ └── CreateClient.php
├── Providers
│ ├── BroadcastServiceProvider.php
│ ├── AppServiceProvider.php
│ └── AuthServiceProvider.php
├── Listeners
│ └── SendEmailWithCredentials.php
├── Services
│ ├── Invoice
│ │ ├── Invoice.php
│ │ └── InvoiceItem.php
│ ├── ProjectService.php
│ ├── NotificationService.php
│ └── UserMentionService.php
├── Policies
│ ├── OwnerCompanyPolicy.php
│ ├── CommentPolicy.php
│ ├── TimeLogPolicy.php
│ ├── UserPolicy.php
│ └── LabelPolicy.php
├── Observers
│ └── CommentObserver.php
└── Console
│ ├── Kernel.php
│ └── Commands
│ ├── PruneNotifications.php
│ └── PruneActivities.php
├── jsconfig.json
├── .gitattributes
├── .prettierrc
├── vite.config.js
├── .gitignore
├── .editorconfig
├── postcss.config.js
├── config
├── favorite.php
├── cors.php
└── view.php
├── routes
├── api.php
├── console.php
└── channels.php
├── .eslintrc.cjs
└── phpunit.xml
/public/favicon.ico:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/database/.gitignore:
--------------------------------------------------------------------------------
1 | *.sqlite*
2 |
--------------------------------------------------------------------------------
/bootstrap/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/logs/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/pint.json:
--------------------------------------------------------------------------------
1 | {
2 | "preset": "laravel"
3 | }
4 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow:
3 |
--------------------------------------------------------------------------------
/storage/app/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !public/
3 | !.gitignore
4 |
--------------------------------------------------------------------------------
/storage/framework/testing/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/views/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/app/public/avatars/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/cache/data/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/storage/framework/sessions/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 |
--------------------------------------------------------------------------------
/resources/views/vendor/mail/text/footer.blade.php:
--------------------------------------------------------------------------------
1 | {{ $slot }}
2 |
--------------------------------------------------------------------------------
/resources/views/vendor/mail/text/panel.blade.php:
--------------------------------------------------------------------------------
1 | {{ $slot }}
2 |
--------------------------------------------------------------------------------
/resources/views/vendor/mail/text/subcopy.blade.php:
--------------------------------------------------------------------------------
1 | {{ $slot }}
2 |
--------------------------------------------------------------------------------
/resources/views/vendor/mail/text/table.blade.php:
--------------------------------------------------------------------------------
1 | {{ $slot }}
2 |
--------------------------------------------------------------------------------
/storage/app/public/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !.gitignore
3 | !avatars
4 |
--------------------------------------------------------------------------------
/storage/framework/cache/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !data/
3 | !.gitignore
4 |
--------------------------------------------------------------------------------
/resources/views/vendor/mail/text/button.blade.php:
--------------------------------------------------------------------------------
1 | {{ $slot }}: {{ $url }}
2 |
--------------------------------------------------------------------------------
/resources/views/vendor/mail/text/header.blade.php:
--------------------------------------------------------------------------------
1 | [{{ $slot }}]({{ $url }})
2 |
--------------------------------------------------------------------------------
/resources/docs/banner.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vstruhar/lara-collab/HEAD/resources/docs/banner.jpg
--------------------------------------------------------------------------------
/resources/js/components/css/Notification.module.css:
--------------------------------------------------------------------------------
1 | .icon {
2 | color: var(--mantine-color-blue-7);
3 | }
--------------------------------------------------------------------------------
/resources/js/utils/enums.js:
--------------------------------------------------------------------------------
1 | export const PricingType = {
2 | HOURLY: 'hourly',
3 | FIXED: 'fixed',
4 | };
5 |
--------------------------------------------------------------------------------
/resources/docs/banner.afphoto:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vstruhar/lara-collab/HEAD/resources/docs/banner.afphoto
--------------------------------------------------------------------------------
/public/vendor/telescope/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vstruhar/lara-collab/HEAD/public/vendor/telescope/favicon.ico
--------------------------------------------------------------------------------
/tests/Unit/ExampleTest.php:
--------------------------------------------------------------------------------
1 | toBeTrue();
5 | });
6 |
--------------------------------------------------------------------------------
/app/Enums/Queue.php:
--------------------------------------------------------------------------------
1 |
2 | {{ Illuminate\Mail\Markdown::parse($slot) }}
3 |
4 |
--------------------------------------------------------------------------------
/resources/docs/screenshots/Task - dark.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vstruhar/lara-collab/HEAD/resources/docs/screenshots/Task - dark.jpeg
--------------------------------------------------------------------------------
/resources/docs/screenshots/Invoice - dark.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vstruhar/lara-collab/HEAD/resources/docs/screenshots/Invoice - dark.jpeg
--------------------------------------------------------------------------------
/resources/docs/screenshots/Task - light.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vstruhar/lara-collab/HEAD/resources/docs/screenshots/Task - light.jpeg
--------------------------------------------------------------------------------
/resources/docs/screenshots/Activity - dark.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vstruhar/lara-collab/HEAD/resources/docs/screenshots/Activity - dark.jpeg
--------------------------------------------------------------------------------
/resources/docs/screenshots/Activity - light.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vstruhar/lara-collab/HEAD/resources/docs/screenshots/Activity - light.jpeg
--------------------------------------------------------------------------------
/resources/docs/screenshots/Dashboard - dark.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vstruhar/lara-collab/HEAD/resources/docs/screenshots/Dashboard - dark.jpeg
--------------------------------------------------------------------------------
/resources/docs/screenshots/Invoice - light.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vstruhar/lara-collab/HEAD/resources/docs/screenshots/Invoice - light.jpeg
--------------------------------------------------------------------------------
/resources/docs/screenshots/My tasks - dark.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vstruhar/lara-collab/HEAD/resources/docs/screenshots/My tasks - dark.jpeg
--------------------------------------------------------------------------------
/resources/docs/screenshots/My tasks - light.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vstruhar/lara-collab/HEAD/resources/docs/screenshots/My tasks - light.jpeg
--------------------------------------------------------------------------------
/resources/docs/screenshots/Projects - dark.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vstruhar/lara-collab/HEAD/resources/docs/screenshots/Projects - dark.jpeg
--------------------------------------------------------------------------------
/resources/docs/screenshots/Projects - light.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vstruhar/lara-collab/HEAD/resources/docs/screenshots/Projects - light.jpeg
--------------------------------------------------------------------------------
/resources/js/utils/task.js:
--------------------------------------------------------------------------------
1 | import dayjs from "dayjs";
2 |
3 | export const isOverdue = (task) => {
4 | return dayjs().isAfter(task.due_on);
5 | };
6 |
--------------------------------------------------------------------------------
/resources/docs/screenshots/Dashboard - light.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vstruhar/lara-collab/HEAD/resources/docs/screenshots/Dashboard - light.jpeg
--------------------------------------------------------------------------------
/resources/docs/screenshots/Project tasks - dark.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vstruhar/lara-collab/HEAD/resources/docs/screenshots/Project tasks - dark.jpeg
--------------------------------------------------------------------------------
/resources/docs/screenshots/Project tasks - light.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/vstruhar/lara-collab/HEAD/resources/docs/screenshots/Project tasks - light.jpeg
--------------------------------------------------------------------------------
/resources/js/layouts/css/ContainerBox.module.css:
--------------------------------------------------------------------------------
1 | .box {
2 |
3 | @mixin light {
4 | background-color: var(--mantine-color-white);
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/resources/js/pages/Auth/css/Login.module.css:
--------------------------------------------------------------------------------
1 | .title {
2 | font-family:
3 | Greycliff CF,
4 | var(--mantine-font-family);
5 | font-weight: 900;
6 | }
7 |
--------------------------------------------------------------------------------
/app/Enums/PricingType.php:
--------------------------------------------------------------------------------
1 | get('/');
5 |
6 | $response->assertStatus(200);
7 | });
8 |
--------------------------------------------------------------------------------
/storage/framework/.gitignore:
--------------------------------------------------------------------------------
1 | compiled.php
2 | config.php
3 | down
4 | events.scanned.php
5 | maintenance.php
6 | routes.php
7 | routes.scanned.php
8 | schedule-*
9 | services.json
10 |
--------------------------------------------------------------------------------
/resources/js/pages/Projects/Tasks/Drawers/css/Comments.module.css:
--------------------------------------------------------------------------------
1 | .comment {
2 | font-size: rem(14);
3 | line-height: rem(14);
4 |
5 | p {
6 | margin: 0;
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/resources/views/vendor/mail/html/header.blade.php:
--------------------------------------------------------------------------------
1 | @props(['url'])
2 |
3 |
8 |
9 |
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": ".",
4 | "paths": {
5 | "@/*": ["resources/js/*"]
6 | }
7 | },
8 | "exclude": ["node_modules", "public"]
9 | }
10 |
--------------------------------------------------------------------------------
/resources/js/utils/domEvents.js:
--------------------------------------------------------------------------------
1 | export const stopOnIgnoreLink = (event) => {
2 | if (
3 | event.target.dataset.ignoreLink ||
4 | event.target.parentNode.dataset.ignoreLink
5 | )
6 | event.preventDefault();
7 | };
8 |
--------------------------------------------------------------------------------
/tests/TestCase.php:
--------------------------------------------------------------------------------
1 |
2 |
3 | |
4 | {{ Illuminate\Mail\Markdown::parse($slot) }}
5 | |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/resources/views/vendor/mail/text/layout.blade.php:
--------------------------------------------------------------------------------
1 | {!! strip_tags($header ?? '') !!}
2 |
3 | {!! strip_tags($slot) !!}
4 | @isset($subcopy)
5 |
6 | {!! strip_tags($subcopy) !!}
7 | @endisset
8 |
9 | {!! strip_tags($footer ?? '') !!}
10 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto eol=lf
2 |
3 | *.blade.php diff=html
4 | *.css diff=css
5 | *.html diff=html
6 | *.md diff=markdown
7 | *.php diff=php
8 |
9 | /.github export-ignore
10 | CHANGELOG.md export-ignore
11 | .styleci.yml export-ignore
12 |
--------------------------------------------------------------------------------
/resources/js/types.ts:
--------------------------------------------------------------------------------
1 | export type User = {
2 | id: BigInteger;
3 | name: String;
4 | email: String;
5 | phone: String;
6 | job_title: String;
7 | avatar: String;
8 | rate: BigInteger;
9 | created_at: String;
10 | };
11 |
--------------------------------------------------------------------------------
/public/vendor/telescope/mix-manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "/app.js": "/app.js?id=140ed4bc5b10bc99492b97668c59272d",
3 | "/app-dark.css": "/app-dark.css?id=b11fa9a28e9d3aeb8c92986f319b3c44",
4 | "/app.css": "/app.css?id=b3ccfbe68f24cff776f83faa8dead721"
5 | }
6 |
--------------------------------------------------------------------------------
/resources/js/utils/axios.js:
--------------------------------------------------------------------------------
1 | import nProgress from "nprogress";
2 |
3 | export const onUploadProgress = (progressEvent) => {
4 | nProgress.set(progressEvent.progress);
5 |
6 | if (progressEvent.progress === 1) {
7 | nProgress.done();
8 | }
9 | };
10 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleAttributePerLine": true,
3 | "printWidth": 100,
4 | "tabWidth": 2,
5 | "bracketSameLine": false,
6 | "singleQuote": true,
7 | "jsxSingleQuote": true,
8 | "trailingComma": "es5",
9 | "arrowParens": "avoid"
10 | }
--------------------------------------------------------------------------------
/resources/js/components/ActionButton.jsx:
--------------------------------------------------------------------------------
1 | import { Button } from "@mantine/core";
2 |
3 | export default function ActionButton({ children, ...props }) {
4 | return (
5 |
8 | );
9 | }
10 |
--------------------------------------------------------------------------------
/resources/css/app.css:
--------------------------------------------------------------------------------
1 | :root[data-mantine-color-scheme=light] {
2 | --mantine-color-text: #343d43;
3 | --mantine-color-gray-filled: var(--mantine-color-gray-3) !important;
4 | --mantine-color-body: var(--mantine-color-gray-0);
5 | --mantine-color-anchor: var(--mantine-color-blue-7);
6 | }
--------------------------------------------------------------------------------
/resources/js/utils/currency.js:
--------------------------------------------------------------------------------
1 | export const money = (amount, currency = 'USD', minimumFractionDigits = 2) => {
2 | const formatter = new Intl.NumberFormat('en-US', {
3 | style: 'currency',
4 | currency,
5 | minimumFractionDigits,
6 | });
7 |
8 | return formatter.format(amount / 100);
9 | };
10 |
--------------------------------------------------------------------------------
/resources/js/components/css/Card.module.css:
--------------------------------------------------------------------------------
1 | .card {
2 | transition: 0.3s ease all;
3 | background-color: light-dark(var(--mantine-color-white), var(--mantine-color-body)) !important;
4 |
5 | @mixin hover {
6 | border: 1px solid light-dark(var(--mantine-color-gray-4), var(--mantine-color-gray-7));
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/resources/js/pages/Projects/Tasks/Index/Filters/css/FilterButton.module.css:
--------------------------------------------------------------------------------
1 | .button {
2 | border: rem(1px) solid light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-6));
3 |
4 | @mixin hover {
5 | border: rem(1px) solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-4));
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/resources/views/vendor/mail/html/footer.blade.php:
--------------------------------------------------------------------------------
1 |
2 | |
3 |
10 | |
11 |
12 |
--------------------------------------------------------------------------------
/resources/js/components/RoleBadge.jsx:
--------------------------------------------------------------------------------
1 | import useRoles from "@/hooks/useRoles";
2 | import { Badge } from "@mantine/core";
3 |
4 | export default function RoleBadge({ role }) {
5 | const { getColor } = useRoles();
6 |
7 | return (
8 |
9 | {role}
10 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/app/Models/Permission.php:
--------------------------------------------------------------------------------
1 |
7 | {children}
8 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/resources/js/hooks/usePreferences.js:
--------------------------------------------------------------------------------
1 | import { useLocalStorage } from "@mantine/hooks";
2 |
3 | export default function usePreferences() {
4 | const [tasksView, setTasksView] = useLocalStorage({
5 | key: "tasks-view",
6 | defaultValue: "list",
7 | getInitialValueInEffect: false,
8 | });
9 |
10 | return {tasksView, setTasksView};
11 | }
12 |
--------------------------------------------------------------------------------
/vite.config.js:
--------------------------------------------------------------------------------
1 | import { defineConfig } from 'vite';
2 | import laravel from 'laravel-vite-plugin';
3 | import react from '@vitejs/plugin-react';
4 |
5 | export default defineConfig({
6 | plugins: [
7 | laravel({
8 | input: 'resources/js/app.jsx',
9 | refresh: true,
10 | }),
11 | react(),
12 | ],
13 | });
14 |
--------------------------------------------------------------------------------
/resources/js/components/Card.jsx:
--------------------------------------------------------------------------------
1 | import { Card as MantineCard } from "@mantine/core";
2 | import classes from "./css/Card.module.css";
3 |
4 | export default function Card({ children, ...props }) {
5 | return (
6 |
7 | {children}
8 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/resources/js/components/TableRowEmpty.jsx:
--------------------------------------------------------------------------------
1 | import { Table, Text } from "@mantine/core";
2 |
3 | export default function TableRowEmpty(props) {
4 | return (
5 |
6 |
7 |
8 | No items were found
9 |
10 |
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.phpunit.cache
2 | /node_modules
3 | /public/build
4 | /public/hot
5 | /public/storage
6 | /storage/*.key
7 | /vendor
8 | .env
9 | .env.backup
10 | .env.production
11 | .phpunit.result.cache
12 | Homestead.json
13 | Homestead.yaml
14 | auth.json
15 | npm-debug.log
16 | yarn-error.log
17 | /.fleet
18 | /.idea
19 | /.vscode
20 | /storage/clockwork
21 | .pnpm-lock.yaml
22 |
--------------------------------------------------------------------------------
/app/Http/Controllers/Controller.php:
--------------------------------------------------------------------------------
1 | {
2 | return columns.filter((c) => c.visible !== false);
3 | };
4 |
5 | export const actionColumnVisibility = (name) => {
6 | return (can(`edit ${name}`) && !route().params.archived) ||
7 | (can(`archive ${name}`) && !route().params.archived) ||
8 | (can(`restore ${name}`) && route().params.archived);
9 | };
10 |
--------------------------------------------------------------------------------
/app/Enums/Invoice.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | |
7 | {{ Illuminate\Mail\Markdown::parse($slot) }}
8 | |
9 |
10 |
11 | |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | charset = utf-8
5 | end_of_line = lf
6 | indent_size = 4
7 | indent_style = space
8 | insert_final_newline = true
9 | trim_trailing_whitespace = true
10 | max_line_length=100
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
14 |
15 | [*.{yml,yaml}]
16 | indent_size = 2
17 |
18 | [*.{js,jsx}]
19 | indent_size = 2
20 |
21 | [docker-compose.yml]
22 | indent_size = 4
23 |
--------------------------------------------------------------------------------
/app/Http/Middleware/EncryptCookies.php:
--------------------------------------------------------------------------------
1 |
13 | */
14 | protected $except = [
15 | //
16 | ];
17 | }
18 |
--------------------------------------------------------------------------------
/resources/js/hooks/useAuthorization.js:
--------------------------------------------------------------------------------
1 | import { usePage } from "@inertiajs/react";
2 |
3 | export default function useAuthorization() {
4 | const {auth} = usePage().props;
5 |
6 | const can = (permission) => {
7 | return auth.user.permissions.includes(permission);
8 | };
9 |
10 | const isAdmin = () => {
11 | return auth.user.roles.includes('admin');
12 | };
13 |
14 | return {can, isAdmin};
15 | }
16 |
--------------------------------------------------------------------------------
/resources/js/components/Label.jsx:
--------------------------------------------------------------------------------
1 | import { ColorSwatch, Group, Text } from "@mantine/core";
2 |
3 | export function Label({ name, color, size = 10, dot = true }) {
4 | return (
5 |
6 | {dot === true && }
7 |
8 | {name}
9 |
10 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/resources/js/layouts/css/UserButton.module.css:
--------------------------------------------------------------------------------
1 | .user {
2 | display: block;
3 | width: 100%;
4 | padding: var(--mantine-spacing-md);
5 | color: light-dark(var(--mantine-color-white), var(--mantine-color-dark-0));
6 | transition: 0.3s ease background-color;
7 |
8 | @mixin hover {
9 | background-color: light-dark(var(--mantine-color-blue-9), var(--mantine-color-dark-8)) !important;
10 | }
11 | }
--------------------------------------------------------------------------------
/app/Http/Middleware/VerifyCsrfToken.php:
--------------------------------------------------------------------------------
1 |
13 | */
14 | protected $except = [
15 | //
16 | ];
17 | }
18 |
--------------------------------------------------------------------------------
/app/Models/Country.php:
--------------------------------------------------------------------------------
1 | get(['id', 'name'])
13 | ->map(fn ($i) => ['value' => (string) $i->id, 'label' => $i->name])
14 | ->toArray();
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/app/Events/UserCreated.php:
--------------------------------------------------------------------------------
1 | whereNull($this->field);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/resources/js/components/css/TableHeader.module.css:
--------------------------------------------------------------------------------
1 | .th {
2 | padding: 0;
3 | }
4 |
5 | .control {
6 | width: 100%;
7 | padding: var(--mantine-spacing-xs) var(--mantine-spacing-md);
8 |
9 | @mixin hover {
10 | background-color: light-dark(var(--mantine-color-gray-0), var(--mantine-color-dark-6));
11 | }
12 | }
13 |
14 | .icon {
15 | width: rem(21px);
16 | height: rem(21px);
17 | border-radius: rem(21px);
18 | }
--------------------------------------------------------------------------------
/app/Models/Filters/WhereInFilter.php:
--------------------------------------------------------------------------------
1 | whereIn($this->field, $this->values);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/resources/js/pages/Account/Notifications/css/Index.module.css:
--------------------------------------------------------------------------------
1 | .notification {
2 | border: 1px solid light-dark(var(--mantine-color-gray-3), var(--mantine-color-dark-5));
3 | padding: 15px;
4 | border-radius: var(--mantine-radius-sm);
5 | transition: 0.3s ease all;
6 |
7 | @mixin hover {
8 | background-color: light-dark(var(--mantine-color-gray-1), var(--mantine-color-dark-6));
9 | opacity: 1 !important;
10 | }
11 | }
--------------------------------------------------------------------------------
/resources/js/pages/Projects/Tasks/Index/Task.jsx:
--------------------------------------------------------------------------------
1 | import usePreferences from "@/hooks/usePreferences";
2 | import TaskCard from "./Task/TaskCard";
3 | import TaskRow from "./Task/TaskRow";
4 |
5 | export default function Task({ task, index }) {
6 | const { tasksView } = usePreferences();
7 |
8 | return tasksView === "list" ? (
9 |
10 | ) : (
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/database/seeders/ClientSeeder.php:
--------------------------------------------------------------------------------
1 | create(['job_title' => 'Client'])
17 | ->each
18 | ->assignRole('client');
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/app/Actions/ClientCompany/UpdateClientCompany.php:
--------------------------------------------------------------------------------
1 | clients()->sync($data['clients']);
13 | }
14 |
15 | return $clientCompany->update($data);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/resources/js/pages/Auth/css/ForgotPassword.module.css:
--------------------------------------------------------------------------------
1 | .title {
2 | font-size: rem(26px);
3 | font-weight: 900;
4 | font-family: Greycliff CF, var(--mantine-font-family);
5 | }
6 |
7 | .controls {
8 | @media (max-width: $mantine-breakpoint-xs) {
9 | flex-direction: column-reverse;
10 | }
11 | }
12 |
13 | .control {
14 | @media (max-width: $mantine-breakpoint-xs) {
15 | width: 100%;
16 | text-align: center;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/resources/js/pages/Auth/css/ResetPassword.module.css:
--------------------------------------------------------------------------------
1 | .title {
2 | font-size: rem(26px);
3 | font-weight: 900;
4 | font-family: Greycliff CF, var(--mantine-font-family);
5 | }
6 |
7 | .controls {
8 | @media (max-width: $mantine-breakpoint-xs) {
9 | flex-direction: column-reverse;
10 | }
11 | }
12 |
13 | .control {
14 | @media (max-width: $mantine-breakpoint-xs) {
15 | width: 100%;
16 | text-align: center;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/app/Providers/BroadcastServiceProvider.php:
--------------------------------------------------------------------------------
1 |
8 |