├── .github ├── CONTRIBUTING.md ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug.yml │ └── config.yml ├── SECURITY.md ├── dependabot.yml └── workflows │ ├── dependabot-auto-merge.yml │ ├── fix-php-code-styling.yml │ └── tests.yml ├── .gitignore ├── .php-cs-fixer.dist.php ├── 3x1io-tomato-accounts.md ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── LICENSE.md ├── README.md ├── SECURITY.md ├── arts ├── 3x1io-tomato-accounts.jpg ├── account-column.png ├── accounts-list.png ├── change-password.png ├── edit-account.png └── send-notifications.png ├── composer.json ├── composer.lock ├── config ├── .gitkeep └── filament-accounts.php ├── database └── migrations │ ├── .gitkeep │ ├── 2023_02_13_134629_create_accounts_table.php │ └── 2024_10_28_143941_add_media_if_not_exists_table.php ├── module.json ├── phpunit.xml ├── pint.json ├── publish └── Account.php ├── resources ├── js │ └── .gitkeep ├── lang │ ├── .gitkeep │ ├── ar │ │ └── messages.php │ └── en │ │ └── messages.php └── views │ ├── .gitkeep │ └── components │ └── account-column.blade.php ├── src ├── Components │ └── AccountColumn.php ├── Console │ ├── .gitkeep │ └── FilamentAccountsInstall.php ├── Export │ └── ExportAccounts.php ├── Facades │ └── FilamentAccounts.php ├── Filament │ └── Resources │ │ ├── AccountResource.php │ │ └── AccountResource │ │ ├── Actions │ │ ├── Components │ │ │ ├── .gitkeep │ │ │ ├── Action.php │ │ │ ├── CreateAction.php │ │ │ ├── DeleteAction.php │ │ │ ├── EditAction.php │ │ │ ├── TypesAction.php │ │ │ └── ViewAction.php │ │ ├── Contracts │ │ │ ├── .gitkeep │ │ │ └── CanRegister.php │ │ ├── CreatePageActions.php │ │ ├── EditPageActions.php │ │ ├── ManagePageActions.php │ │ └── ViewPageActions.php │ │ ├── Form │ │ ├── AccountForm.php │ │ └── Components │ │ │ ├── .gitkeep │ │ │ ├── Address.php │ │ │ ├── Avatar.php │ │ │ ├── Component.php │ │ │ ├── Email.php │ │ │ ├── IsActive.php │ │ │ ├── IsLogin.php │ │ │ ├── LoginBy.php │ │ │ ├── Name.php │ │ │ ├── Password.php │ │ │ ├── PasswordConfirmation.php │ │ │ ├── Phone.php │ │ │ └── Type.php │ │ ├── InfoList │ │ ├── AccountInfoList.php │ │ └── Entries │ │ │ ├── .gitkeep │ │ │ ├── Address.php │ │ │ ├── Avatar.php │ │ │ ├── Email.php │ │ │ ├── Entry.php │ │ │ ├── IsActive.php │ │ │ ├── IsLogin.php │ │ │ ├── LoginBy.php │ │ │ ├── Name.php │ │ │ ├── Phone.php │ │ │ └── Type.php │ │ ├── Pages │ │ ├── AccountTypes.php │ │ ├── CreateAccount.php │ │ ├── EditAccount.php │ │ ├── ListAccounts.php │ │ ├── ManageAccounts.php │ │ └── ViewAccount.php │ │ └── Table │ │ ├── AccountActions.php │ │ ├── AccountBulkActions.php │ │ ├── AccountFilters.php │ │ ├── AccountHeaderActions.php │ │ ├── AccountTable.php │ │ ├── Actions │ │ ├── .gitkeep │ │ ├── Action.php │ │ ├── ChangePasswordAction.php │ │ ├── DeleteAction.php │ │ ├── EditAction.php │ │ ├── ImpersonateAction.php │ │ └── ViewAction.php │ │ ├── BulkActions │ │ ├── .gitkeep │ │ ├── Action.php │ │ └── DeleteAction.php │ │ ├── Columns │ │ ├── .gitkeep │ │ ├── Account.php │ │ ├── Column.php │ │ ├── CreatedAt.php │ │ ├── Email.php │ │ ├── Id.php │ │ ├── IsActive.php │ │ ├── IsLogin.php │ │ ├── Name.php │ │ ├── Phone.php │ │ ├── Type.php │ │ └── UpdatedAt.php │ │ ├── Filters │ │ ├── .gitkeep │ │ ├── Filter.php │ │ ├── IsActive.php │ │ ├── IsLogin.php │ │ ├── Trashed.php │ │ └── Type.php │ │ └── HeaderActions │ │ ├── .gitkeep │ │ ├── Action.php │ │ ├── ExportAction.php │ │ └── ImportAction.php ├── FilamentAccountsPlugin.php ├── FilamentAccountsServiceProvider.php ├── Import │ └── ImportAccounts.php ├── Models │ ├── .gitkeep │ └── Account.php └── Services │ └── FilamentAccountsServices.php └── tests ├── Pest.php ├── database ├── database.sqlite └── factories │ ├── AccountFactory.php │ └── UserFactory.php └── src ├── AccountResourceTest.php ├── AdminPanelProvider.php ├── DebugTest.php ├── Models ├── Account.php └── User.php ├── PluginTest.php └── TestCase.php /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are **welcome** and will be fully **credited**. 4 | 5 | Please read and understand the contribution guide before creating an issue or pull request. 6 | 7 | ## Etiquette 8 | 9 | This project is open source, and as such, the maintainers give their free time to build and maintain the source code 10 | held within. They make the code freely available in the hope that it will be of use to other developers. It would be 11 | extremely unfair for them to suffer abuse or anger for their hard work. 12 | 13 | Please be considerate towards maintainers when raising issues or presenting pull requests. Let's show the 14 | world that developers are civilized and selfless people. 15 | 16 | It's the duty of the maintainer to ensure that all submissions to the project are of sufficient 17 | quality to benefit the project. Many developers have different skills, strengths, and weaknesses. Respect the maintainer's decision, and do not be upset or abusive if your submission is not used. 18 | 19 | ## Viability 20 | 21 | When requesting or submitting new features, first consider whether it might be useful to others. Open 22 | source projects are used by many developers, who may have entirely different needs to your own. Think about 23 | whether or not your feature is likely to be used by other users of the project. 24 | 25 | ## Procedure 26 | 27 | Before filing an issue: 28 | 29 | - Attempt to replicate the problem, to ensure that it wasn't a coincidental incident. 30 | - Check to make sure your feature suggestion isn't already present within the project. 31 | - Check the pull requests tab to ensure that the bug doesn't have a fix in progress. 32 | - Check the pull requests tab to ensure that the feature isn't already in progress. 33 | 34 | Before submitting a pull request: 35 | 36 | - Check the codebase to ensure that your feature doesn't already exist. 37 | - Check the pull requests to ensure that another person hasn't already submitted the feature or fix. 38 | 39 | ## Requirements 40 | 41 | If the project maintainer has any additional requirements, you will find them listed here. 42 | 43 | - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](https://pear.php.net/package/PHP_CodeSniffer). 44 | 45 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests. 46 | 47 | - **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. 48 | 49 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](https://semver.org/). Randomly breaking public APIs is not an option. 50 | 51 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. 52 | 53 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](https://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. 54 | 55 | **Happy coding**! 56 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [3x1io] 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Report an Issue or Bug with the Package 3 | title: "[Bug]: " 4 | labels: ["bug"] 5 | body: 6 | - type: markdown 7 | attributes: 8 | value: | 9 | We're sorry to hear you have a problem. Can you help us solve it by providing the following details. 10 | - type: textarea 11 | id: what-happened 12 | attributes: 13 | label: What happened? 14 | description: What did you expect to happen? 15 | placeholder: I cannot currently do X thing because when I do, it breaks X thing. 16 | validations: 17 | required: true 18 | - type: textarea 19 | id: how-to-reproduce 20 | attributes: 21 | label: How to reproduce the bug 22 | description: How did this occur, please add any config values used and provide a set of reliable steps if possible. 23 | placeholder: When I do X I see Y. 24 | validations: 25 | required: true 26 | - type: input 27 | id: package-version 28 | attributes: 29 | label: Package Version 30 | description: What version of our Package are you running? Please be as specific as possible 31 | placeholder: 2.0.0 32 | validations: 33 | required: true 34 | - type: input 35 | id: php-version 36 | attributes: 37 | label: PHP Version 38 | description: What version of PHP are you running? Please be as specific as possible 39 | placeholder: 8.2.0 40 | validations: 41 | required: true 42 | - type: input 43 | id: laravel-version 44 | attributes: 45 | label: Laravel Version 46 | description: What version of Laravel are you running? Please be as specific as possible 47 | placeholder: 9.0.0 48 | validations: 49 | required: true 50 | - type: dropdown 51 | id: operating-systems 52 | attributes: 53 | label: Which operating systems does with happen with? 54 | description: You may select more than one. 55 | multiple: true 56 | options: 57 | - macOS 58 | - Windows 59 | - Linux 60 | - type: textarea 61 | id: notes 62 | attributes: 63 | label: Notes 64 | description: Use this field to provide any other notes that you feel might be relevant to the issue. 65 | validations: 66 | required: false 67 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Ask a question 4 | url: https://github.com/tomatophp/filament-accounts/discussions/new?category=q-a 5 | about: Ask the community for help 6 | - name: Request a feature 7 | url: https://github.com/tomatophp/filament-accounts/discussions/new?category=ideas 8 | about: Share ideas for new features 9 | - name: Report a security issue 10 | url: https://github.com/tomatophp/filament-accounts/security/policy 11 | about: Learn how to notify us for sensitive bugs 12 | -------------------------------------------------------------------------------- /.github/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | If you discover any security related issues, please email info@3x1.io instead of using the issue tracker. 4 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Please see the documentation for all configuration options: 2 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 3 | 4 | version: 2 5 | updates: 6 | 7 | - package-ecosystem: "github-actions" 8 | directory: "/" 9 | schedule: 10 | interval: "weekly" 11 | labels: 12 | - "dependencies" 13 | -------------------------------------------------------------------------------- /.github/workflows/dependabot-auto-merge.yml: -------------------------------------------------------------------------------- 1 | name: dependabot-auto-merge 2 | on: pull_request_target 3 | 4 | permissions: 5 | pull-requests: write 6 | contents: write 7 | 8 | jobs: 9 | dependabot: 10 | runs-on: ubuntu-latest 11 | if: ${{ github.actor == 'dependabot[bot]' }} 12 | steps: 13 | 14 | - name: Dependabot metadata 15 | id: metadata 16 | uses: dependabot/fetch-metadata@v2.4.0 17 | with: 18 | github-token: "${{ secrets.GITHUB_TOKEN }}" 19 | 20 | - name: Auto-merge Dependabot PRs for semver-minor updates 21 | if: ${{steps.metadata.outputs.update-type == 'version-update:semver-minor'}} 22 | run: gh pr merge --auto --merge "$PR_URL" 23 | env: 24 | PR_URL: ${{github.event.pull_request.html_url}} 25 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 26 | 27 | - name: Auto-merge Dependabot PRs for semver-patch updates 28 | if: ${{steps.metadata.outputs.update-type == 'version-update:semver-patch'}} 29 | run: gh pr merge --auto --merge "$PR_URL" 30 | env: 31 | PR_URL: ${{github.event.pull_request.html_url}} 32 | GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} 33 | -------------------------------------------------------------------------------- /.github/workflows/fix-php-code-styling.yml: -------------------------------------------------------------------------------- 1 | name: 'PHP Code Styling' 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - master 8 | paths: 9 | - '**.php' 10 | 11 | permissions: 12 | contents: write 13 | 14 | jobs: 15 | lint: 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Checkout code 19 | uses: actions/checkout@v4 20 | with: 21 | ref: ${{ github.head_ref }} 22 | 23 | - name: Fix PHP code style issues 24 | uses: aglipanci/laravel-pint-action@v2 25 | 26 | - name: Commit changes 27 | uses: stefanzweifel/git-auto-commit-action@v5 28 | with: 29 | commit_message: "Format Code" 30 | commit_user_name: 'GitHub Actions' 31 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: "Tests" 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - master 8 | paths: 9 | - '**.php' 10 | pull_request: 11 | types: 12 | - opened 13 | - synchronize 14 | branches: 15 | - master 16 | paths: 17 | - '**.php' 18 | - '.github/workflows/tests.yml' 19 | - 'phpunit.xml.dist' 20 | - 'composer.json' 21 | - 'composer.lock' 22 | 23 | jobs: 24 | test: 25 | runs-on: ${{ matrix.os }} 26 | strategy: 27 | fail-fast: true 28 | matrix: 29 | os: [ubuntu-latest] 30 | php: [8.3, 8.2, 8.1] 31 | laravel: [11.*, 10.*] 32 | stability: [prefer-stable] 33 | include: 34 | - laravel: 11.* 35 | testbench: 9.* 36 | carbon: 3.* 37 | collision: 8.* 38 | - laravel: 10.* 39 | testbench: 8.* 40 | carbon: 2.* 41 | collision: 7.* 42 | exclude: 43 | - laravel: 11.* 44 | php: 8.1 45 | name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }} 46 | steps: 47 | - name: Checkout Code 48 | uses: actions/checkout@v4 49 | 50 | - name: Cache Dependencies 51 | uses: actions/cache@v4 52 | with: 53 | path: ~/.composer/cache/files 54 | key: dependencies-laravel-${{ matrix.laravel }}-php-${{ matrix.php }}-composer-${{ hashFiles('composer.json') }} 55 | 56 | - name: Setup PHP 57 | uses: shivammathur/setup-php@v2 58 | with: 59 | php-version: ${{ matrix.php }} 60 | extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo 61 | coverage: none 62 | 63 | - name: Install Dependencies 64 | run: | 65 | echo "::add-matcher::${{ runner.tool_cache }}/php.json" 66 | echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" 67 | 68 | - name: Install Dependencies 69 | run: | 70 | composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" "nesbot/carbon:${{ matrix.carbon }}" "nunomaduro/collision:${{ matrix.collision }}" --no-interaction --no-update 71 | composer update --${{ matrix.stability }} --prefer-dist --no-interaction 72 | 73 | - name: Execute tests 74 | run: vendor/bin/pest 75 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.phpunit.cache 2 | /node_modules 3 | /public/build 4 | /public/hot 5 | /public/storage 6 | /storage/*.key 7 | /storage/pail 8 | /vendor 9 | .env 10 | .env.backup 11 | .env.production 12 | .phpactor.json 13 | .phpunit.result.cache 14 | .DS_Store 15 | Homestead.json 16 | Homestead.yaml 17 | auth.json 18 | npm-debug.log 19 | yarn-error.log 20 | /.fleet 21 | /.idea 22 | /.vscode 23 | /.zed 24 | -------------------------------------------------------------------------------- /.php-cs-fixer.dist.php: -------------------------------------------------------------------------------- 1 | notPath('bootstrap/*') 5 | ->notPath('storage/*') 6 | ->notPath('resources/view/mail/*') 7 | ->in([ 8 | __DIR__ . '/src', 9 | __DIR__ . '/tests', 10 | ]) 11 | ->name('*.php') 12 | ->notName('*.blade.php') 13 | ->ignoreDotFiles(true) 14 | ->ignoreVCS(true); 15 | 16 | return (new PhpCsFixer\Config()) 17 | ->setRules([ 18 | '@PSR2' => true, 19 | 'array_syntax' => ['syntax' => 'short'], 20 | 'ordered_imports' => ['sort_algorithm' => 'alpha'], 21 | 'no_unused_imports' => true, 22 | 'not_operator_with_successor_space' => true, 23 | 'trailing_comma_in_multiline' => true, 24 | 'phpdoc_scalar' => true, 25 | 'unary_operator_spaces' => true, 26 | 'binary_operator_spaces' => true, 27 | 'blank_line_before_statement' => [ 28 | 'statements' => ['break', 'continue', 'declare', 'return', 'throw', 'try'], 29 | ], 30 | 'phpdoc_single_line_var_spacing' => true, 31 | 'phpdoc_var_without_name' => true, 32 | 'method_argument_space' => [ 33 | 'on_multiline' => 'ensure_fully_multiline', 34 | 'keep_multiple_spaces_after_comma' => true, 35 | ] 36 | ]) 37 | ->setFinder($finder); 38 | -------------------------------------------------------------------------------- /3x1io-tomato-accounts.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Accounts Builder 3 | slug: 3x1io-tomato-accounts 4 | author_slug: 3x1io 5 | categories: [developer-tool] 6 | description: Manage your multi accounts inside your app using 1 table with multi auth and a lot of integrations 7 | discord_url: 8 | docs_url: https://raw.githubusercontent.com/tomatophp/filament-accounts/master/README.md 9 | github_repository: tomatophp/filament-accounts 10 | has_dark_theme: true 11 | has_translations: true 12 | versions: [3] 13 | publish_date: 2024-04-18 14 | --- 15 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomatophp/filament-accounts/7f5f11765de2781e119f826163e9dcb7a8c1a347/CHANGELOG.md -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | . 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Screenshot](https://raw.githubusercontent.com/tomatophp/filament-accounts/master/arts/3x1io-tomato-accounts.jpg) 2 | 3 | # Filament Accounts Builder 4 | 5 | [![Dependabot Updates](https://github.com/tomatophp/filament-accounts/actions/workflows/dependabot/dependabot-updates/badge.svg)](https://github.com/tomatophp/filament-accounts/actions/workflows/dependabot/dependabot-updates) 6 | [![PHP Code Styling](https://github.com/tomatophp/filament-accounts/actions/workflows/fix-php-code-styling.yml/badge.svg)](https://github.com/tomatophp/filament-accounts/actions/workflows/fix-php-code-styling.yml) 7 | [![Tests](https://github.com/tomatophp/filament-accounts/actions/workflows/tests.yml/badge.svg)](https://github.com/tomatophp/filament-accounts/actions/workflows/tests.yml) 8 | [![Latest Stable Version](https://poser.pugx.org/tomatophp/filament-accounts/version.svg)](https://packagist.org/packages/tomatophp/filament-accounts) 9 | [![License](https://poser.pugx.org/tomatophp/filament-accounts/license.svg)](https://packagist.org/packages/tomatophp/filament-accounts) 10 | [![Downloads](https://poser.pugx.org/tomatophp/filament-accounts/d/total.svg)](https://packagist.org/packages/tomatophp/filament-accounts) 11 | 12 | Manage your multi accounts inside your app using 1 table with multi auth and a lot of integrations 13 | 14 | > [!CAUTION] 15 | > Don't update to v2.3 if you are using v2.2 or less because you will lose some features but you can update and use this features from integrated packages. 16 | 17 | ## Screenshots 18 | 19 | ![Accounts List](https://raw.githubusercontent.com/tomatophp/filament-accounts/master/arts/accounts-list.png) 20 | ![Change Password](https://raw.githubusercontent.com/tomatophp/filament-accounts/master/arts/change-password.png) 21 | ![Send Notifications](https://raw.githubusercontent.com/tomatophp/filament-accounts/master/arts/send-notifications.png) 22 | ![Edit Account](https://raw.githubusercontent.com/tomatophp/filament-accounts/master/arts/edit-account.png) 23 | 24 | ## Features 25 | 26 | - [x] Accounts Manager 27 | - [x] Account Types `not tested` 28 | - [x] Account Login By `not tested` 29 | - [x] Account Active/Block `not tested` 30 | - [x] Account Avatar `not tested` 31 | - [x] Account Impersonate Integration `not tested` 32 | - [x] Account Table Column `not tested` 33 | - [x] Export `not tested` 34 | - [x] Import `not tested` 35 | - [ ] Account Filament Alerts Integration 36 | - [ ] Account Teams 37 | - [ ] Google Contacts Integrations 38 | 39 | ## Use Case 40 | 41 | you can use this package if you like to build a CRM or a multi-accounts app 42 | 43 | ## Installation 44 | 45 | ```bash 46 | composer require tomatophp/filament-accounts 47 | ``` 48 | 49 | after install your package please run this command 50 | 51 | ```bash 52 | php artisan filament-accounts:install 53 | ``` 54 | 55 | if you are not using this package as a plugin please register the plugin on `/app/Providers/Filament/AdminPanelProvider.php` 56 | 57 | ```php 58 | ->plugin(\TomatoPHP\FilamentAccounts\FilamentAccountsPlugin::make()) 59 | ``` 60 | 61 | ## Publish Account Model 62 | 63 | you can publish your account model to add other relations or implement some interfaces by using this command 64 | 65 | ```bash 66 | php artisan vendor:publish --tag="filament-accounts-model" 67 | ``` 68 | 69 | now go to your `filament-accounts.php` config file and change the model value to the new one. 70 | 71 | if you don't find it you can publish it 72 | 73 | ``` 74 | php artisan vendor:publish --tag="filament-accounts-config" 75 | ``` 76 | 77 | ## Add Accounts Guard 78 | 79 | now you need to add a new guard to your auth.php config like this 80 | 81 | ```php 82 | [ 91 | "notifications" => false, 92 | "loginBy" => false, 93 | "avatar" => false, 94 | "types" => false, 95 | "teams" => false, 96 | "impersonate" => [ 97 | 'active'=> false, 98 | 'redirect' => '/app', 99 | ], 100 | ], 101 | 102 | /* 103 | * Accounts Configurations 104 | * 105 | * login_by: Login By Phone or Email 106 | */ 107 | "login_by" => "email", 108 | 109 | /* 110 | * Accounts Configurations 111 | * 112 | * model: User Model Class 113 | */ 114 | "model" => \TomatoPHP\FilamentAccounts\Models\Account::class, 115 | 116 | 117 | 118 | ]; 119 | 120 | ``` 121 | 122 | ## Usage 123 | 124 | this plugin makes it easy to make a starting point for your app if this app has customers to manage 125 | 126 | but here is the problem, every app has a different way of managing customers, so we built a Facade service to control the way you want to manage your customers 127 | 128 | ### Use Avatar 129 | 130 | add this method to your plugin in `AdminPanelProvider.php` 131 | 132 | ```php 133 | ->plugin( 134 | \TomatoPHP\FilamentAccounts\FilamentAccountsPlugin::make() 135 | ->useAvatar() 136 | ) 137 | ``` 138 | 139 | ## Hide Resource 140 | 141 | just allow `useResource->()` on the plugin 142 | 143 | ```php 144 | ->plugin(\TomatoPHP\FilamentAccounts\FilamentAccountsPlugin::make() 145 | ->useResource(false) 146 | ) 147 | ``` 148 | 149 | ## Use Filament Types 150 | 151 | just allow `->useResource()` on the plugin 152 | 153 | ```php 154 | ->plugin(\TomatoPHP\FilamentAccounts\FilamentAccountsPlugin::make() 155 | ->useResource() 156 | ) 157 | ``` 158 | 159 | ## Show Address Field 160 | 161 | you can show or hide address field on the create or edit form by using this code 162 | 163 | ```php 164 | 165 | ->plugin(\TomatoPHP\FilamentAccounts\FilamentAccountsPlugin::make() 166 | ->showAddressField() 167 | ) 168 | ``` 169 | 170 | ## Show Type Field 171 | 172 | you can show or hide type field on the create or edit form by using this code 173 | 174 | ```php 175 | 176 | ->plugin(\TomatoPHP\FilamentAccounts\FilamentAccountsPlugin::make() 177 | ->showTypeField() 178 | ) 179 | ``` 180 | 181 | ## Attach Relation To Accounts 182 | 183 | you can attach a new relation to the accounts relations manager by just passing the relation class to the facade service method 184 | 185 | ```php 186 | use TomatoPHP\FilamentAccounts\Facades\FilamentAccounts; 187 | 188 | public function boot() 189 | { 190 | FilamentAccounts::register([ 191 | AccountOrdersRelationManager::make() 192 | ]); 193 | } 194 | ``` 195 | 196 | ## Use Export & Import Actions 197 | 198 | now on your main panel provider add `->useExport()` , `->useImport()` to the plugin 199 | 200 | ```php 201 | ->plugin(\TomatoPHP\FilamentAccounts\FilamentAccountsPlugin::make() 202 | ... 203 | ->useExport() 204 | ->useImport() 205 | ) 206 | ``` 207 | 208 | ## Use Account Column 209 | 210 | ![Account Column](https://raw.githubusercontent.com/tomatophp/filament-accounts/master/arts/account-column.png) 211 | 212 | you can use the account column in any table by using this code 213 | 214 | ```php 215 | public static function table(Table $table): Table 216 | { 217 | return $table 218 | ->columns([ 219 | AccountColumn::make('account.id'), 220 | ]); 221 | } 222 | ``` 223 | 224 | just pass the account id to the column 225 | 226 | 227 | ### Use Filament Impersonate 228 | 229 | you can use the impersonate to impersonate the user by install it first 230 | 231 | ```bash 232 | composer require stechstudio/filament-impersonate 233 | ``` 234 | 235 | now on your main panel provider add `->useImpersonate()` , `->impersonateRedirect('/app')` to the plugin 236 | 237 | ```php 238 | ->plugin(\TomatoPHP\FilamentAccounts\FilamentAccountsPlugin::make() 239 | ... 240 | ->useImpersonate() 241 | ->impersonateRedirect('/app') 242 | ) 243 | ``` 244 | 245 | now clear your config 246 | 247 | ```bash 248 | php artisan config:cache 249 | ``` 250 | 251 | for more information check the [Filament Impersonate](https://github.com/stechstudio/filament-impersonate) 252 | 253 | ## Testing 254 | 255 | if you like to run `PEST` testing just use this command 256 | 257 | ```bash 258 | composer test 259 | ``` 260 | 261 | ## Code Style 262 | 263 | if you like to fix the code style just use this command 264 | 265 | ```bash 266 | composer format 267 | ``` 268 | 269 | ## PHPStan 270 | 271 | if you like to check the code by `PHPStan` just use this command 272 | 273 | ```bash 274 | composer analyse 275 | ``` 276 | 277 | ## Other Filament Packages 278 | 279 | Checkout our [Awesome TomatoPHP](https://github.com/tomatophp/awesome) 280 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomatophp/filament-accounts/7f5f11765de2781e119f826163e9dcb7a8c1a347/SECURITY.md -------------------------------------------------------------------------------- /arts/3x1io-tomato-accounts.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomatophp/filament-accounts/7f5f11765de2781e119f826163e9dcb7a8c1a347/arts/3x1io-tomato-accounts.jpg -------------------------------------------------------------------------------- /arts/account-column.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomatophp/filament-accounts/7f5f11765de2781e119f826163e9dcb7a8c1a347/arts/account-column.png -------------------------------------------------------------------------------- /arts/accounts-list.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomatophp/filament-accounts/7f5f11765de2781e119f826163e9dcb7a8c1a347/arts/accounts-list.png -------------------------------------------------------------------------------- /arts/change-password.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomatophp/filament-accounts/7f5f11765de2781e119f826163e9dcb7a8c1a347/arts/change-password.png -------------------------------------------------------------------------------- /arts/edit-account.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomatophp/filament-accounts/7f5f11765de2781e119f826163e9dcb7a8c1a347/arts/edit-account.png -------------------------------------------------------------------------------- /arts/send-notifications.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomatophp/filament-accounts/7f5f11765de2781e119f826163e9dcb7a8c1a347/arts/send-notifications.png -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tomatophp/filament-accounts", 3 | "type": "library", 4 | "description": "Manage your multi accounts inside your app using 1 table with multi auth and a lot of integrations", 5 | "keywords": [ 6 | "php", 7 | "laravel", 8 | "accounts", 9 | "crm", 10 | "contacts", 11 | "notifications", 12 | "api", 13 | "filament" 14 | ], 15 | "license": "MIT", 16 | "autoload": { 17 | "psr-4": { 18 | "TomatoPHP\\FilamentAccounts\\": "src/" 19 | } 20 | }, 21 | "autoload-dev": { 22 | "psr-4": { 23 | "TomatoPHP\\FilamentAccounts\\Tests\\": "tests/src/", 24 | "TomatoPHP\\FilamentAccounts\\Tests\\Database\\Factories\\": "tests/database/factories" 25 | } 26 | }, 27 | "extra": { 28 | "laravel": { 29 | "providers": [ 30 | "TomatoPHP\\FilamentAccounts\\FilamentAccountsServiceProvider" 31 | ] 32 | } 33 | }, 34 | "authors": [ 35 | { 36 | "name": "Fady Mondy", 37 | "email": "info@3x1.io" 38 | } 39 | ], 40 | "scripts": { 41 | "testbench": "vendor/bin/testbench package:discover --ansi", 42 | "analyse": "vendor/bin/phpstan analyse src tests", 43 | "test": "vendor/bin/pest", 44 | "test-coverage": "vendor/bin/pest --coverage", 45 | "format": "vendor/bin/pint" 46 | }, 47 | "config": { 48 | "sort-packages": true, 49 | "allow-plugins": { 50 | "pestphp/pest-plugin": true, 51 | "phpstan/extension-installer": true 52 | } 53 | }, 54 | "require": { 55 | "php": "^8.1|^8.2", 56 | "tomatophp/console-helpers": "^1.1", 57 | "filament/filament": "^3.2", 58 | "filament/notifications": "^3.2", 59 | "tomatophp/filament-types": "^2.0", 60 | "maatwebsite/excel": "^3.1", 61 | "filament/spatie-laravel-media-library-plugin": "^3.2" 62 | }, 63 | "require-dev": { 64 | "laravel/pint": "^1.18", 65 | "livewire/livewire": "^2.10|^3.0", 66 | "nunomaduro/larastan": "^2.9", 67 | "orchestra/testbench": "^9.5", 68 | "pestphp/pest": "^2.36", 69 | "pestphp/pest-plugin-laravel": "^2.4", 70 | "pestphp/pest-plugin-livewire": "^2.1", 71 | "phpstan/extension-installer": "^1.4", 72 | "phpstan/phpstan-deprecation-rules": "^1.2", 73 | "phpstan/phpstan-phpunit": "^1.4" 74 | }, 75 | "version": "2.3.3" 76 | } 77 | -------------------------------------------------------------------------------- /config/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomatophp/filament-accounts/7f5f11765de2781e119f826163e9dcb7a8c1a347/config/.gitkeep -------------------------------------------------------------------------------- /config/filament-accounts.php: -------------------------------------------------------------------------------- 1 | [ 10 | 'loginBy' => false, 11 | 'avatar' => false, 12 | 'types' => false, 13 | 'teams' => false, 14 | 'impersonate' => [ 15 | 'active' => false, 16 | 'redirect' => '/app', 17 | ], 18 | ], 19 | 20 | /* 21 | * Accounts Configurations 22 | * 23 | * login_by: Login By Phone or Email 24 | */ 25 | 'login_by' => 'email', 26 | 27 | /* 28 | * Accounts Configurations 29 | * 30 | * model: User Model Class 31 | */ 32 | 'model' => \TomatoPHP\FilamentAccounts\Models\Account::class, 33 | 34 | /* 35 | * Use Simple Resource 36 | * 37 | * simple: Enable/Disable Simple Resource 38 | */ 39 | 'simple' => true, 40 | 41 | /* 42 | * Custom Resource 43 | * 44 | * to custom resource classes 45 | */ 46 | 'resource' => [ 47 | 'table' => [ 48 | 'class' => \TomatoPHP\FilamentAccounts\Filament\Resources\AccountResource\Table\AccountTable::class, 49 | 'filters' => \TomatoPHP\FilamentAccounts\Filament\Resources\AccountResource\Table\AccountFilters::class, 50 | 'actions' => \TomatoPHP\FilamentAccounts\Filament\Resources\AccountResource\Table\AccountActions::class, 51 | 'bulkActions' => \TomatoPHP\FilamentAccounts\Filament\Resources\AccountResource\Table\AccountBulkActions::class, 52 | 'headerActions' => \TomatoPHP\FilamentAccounts\Filament\Resources\AccountResource\Table\AccountHeaderActions::class, 53 | ], 54 | 'form' => [ 55 | 'class' => \TomatoPHP\FilamentAccounts\Filament\Resources\AccountResource\Form\AccountForm::class, 56 | ], 57 | 'infolist' => [ 58 | 'class' => \TomatoPHP\FilamentAccounts\Filament\Resources\AccountResource\InfoList\AccountInfoList::class, 59 | ], 60 | 'pages' => [ 61 | 'list' => \TomatoPHP\FilamentAccounts\Filament\Resources\AccountResource\Actions\ManagePageActions::class, 62 | 'create' => \TomatoPHP\FilamentAccounts\Filament\Resources\AccountResource\Actions\CreatePageActions::class, 63 | 'edit' => \TomatoPHP\FilamentAccounts\Filament\Resources\AccountResource\Actions\EditPageActions::class, 64 | 'view' => \TomatoPHP\FilamentAccounts\Filament\Resources\AccountResource\Actions\ViewPageActions::class, 65 | ], 66 | ], 67 | ]; 68 | -------------------------------------------------------------------------------- /database/migrations/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomatophp/filament-accounts/7f5f11765de2781e119f826163e9dcb7a8c1a347/database/migrations/.gitkeep -------------------------------------------------------------------------------- /database/migrations/2023_02_13_134629_create_accounts_table.php: -------------------------------------------------------------------------------- 1 | id(); 18 | $table->string('type')->default('account')->nullable(); 19 | $table->unsignedBigInteger('parent_id')->nullable(); 20 | 21 | $table->string('name')->nullable(); 22 | $table->string('username')->unique(); 23 | $table->string('email')->nullable(); 24 | $table->string('phone')->nullable(); 25 | $table->string('loginBy')->default('email')->nullable(); 26 | $table->text('address')->nullable(); 27 | $table->string('lang', 10)->nullable(); 28 | 29 | // Login 30 | $table->string('password')->nullable(); 31 | $table->string('otp_code')->nullable(); 32 | $table->dateTime('otp_activated_at')->nullable(); 33 | $table->dateTime('last_login')->nullable(); 34 | $table->longText('agent')->nullable(); 35 | $table->string('host')->nullable(); 36 | 37 | // Options 38 | $table->boolean('is_login')->default(0)->nullable(); 39 | $table->boolean('is_active')->default(false); 40 | $table->boolean('is_notification_active')->default(true); 41 | 42 | $table->softDeletes(); 43 | $table->timestamps(); 44 | }); 45 | } 46 | 47 | /** 48 | * Reverse the migrations. 49 | * 50 | * @return void 51 | */ 52 | public function down() 53 | { 54 | Schema::dropIfExists('accounts'); 55 | } 56 | }; 57 | -------------------------------------------------------------------------------- /database/migrations/2024_10_28_143941_add_media_if_not_exists_table.php: -------------------------------------------------------------------------------- 1 | id(); 19 | 20 | $table->morphs('model'); 21 | $table->uuid()->nullable()->unique(); 22 | $table->string('collection_name'); 23 | $table->string('name'); 24 | $table->string('file_name'); 25 | $table->string('mime_type')->nullable(); 26 | $table->string('disk'); 27 | $table->string('conversions_disk')->nullable(); 28 | $table->unsignedBigInteger('size'); 29 | $table->json('manipulations'); 30 | $table->json('custom_properties'); 31 | $table->json('generated_conversions'); 32 | $table->json('responsive_images'); 33 | $table->unsignedInteger('order_column')->nullable()->index(); 34 | 35 | $table->nullableTimestamps(); 36 | }); 37 | } 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /module.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "FilamentAccounts", 3 | "alias": "filament-accounts", 4 | "description": { 5 | "ar": "قم بادارة جميع العملاء والحسابات الخاصة بالنظام من مكان واحد", 6 | "en": "Manage your multi accounts inside your app using 1 table with multi auth and a lot of integrations", 7 | "gr": "Manage your multi accounts inside your app using 1 table with multi auth and a lot of integrations", 8 | "sp": "Manage your multi accounts inside your app using 1 table with multi auth and a lot of integrations" 9 | }, 10 | "keywords": [], 11 | "priority": 0, 12 | "providers": [ 13 | "TomatoPHP\\FilamentAccounts\\FilamentAccountsServiceProvider" 14 | ], 15 | "files": [], 16 | "title": { 17 | "ar": "الحسابات", 18 | "en": "Accounts Builder", 19 | "gr": "Accounts Builder", 20 | "sp": "Accounts Builder" 21 | }, 22 | "color": "#007dff", 23 | "icon": "heroicon-c-user-circle", 24 | "placeholder": "https://raw.githubusercontent.com/tomatophp/filament-accounts/master/arts/3x1io-tomato-accounts.jpg", 25 | "type": "plugin", 26 | "version": "v2.3.0", 27 | "github" : "https://github.com/tomatophp/filament-accounts", 28 | "docs" : "https://github.com/tomatophp/filament-accounts" 29 | } 30 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 14 | ./tests/ 15 | 16 | 17 | 18 | 19 | ./src 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /pint.json: -------------------------------------------------------------------------------- 1 | { 2 | "preset": "laravel", 3 | "rules": { 4 | "blank_line_before_statement": true, 5 | "concat_space": { 6 | "spacing": "one" 7 | }, 8 | "method_argument_space": true, 9 | "single_trait_insert_per_statement": true, 10 | "types_spaces": { 11 | "space": "single" 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /publish/Account.php: -------------------------------------------------------------------------------- 1 | 'boolean', 68 | 'is_active' => 'boolean', 69 | ]; 70 | 71 | protected $dates = [ 72 | 'deleted_at', 73 | 'created_at', 74 | 'updated_at', 75 | 'otp_activated_at', 76 | 'last_login', 77 | ]; 78 | 79 | protected $hidden = [ 80 | 'password', 81 | 'remember_token', 82 | 'otp_code', 83 | 'otp_activated_at', 84 | 'host', 85 | 'agent', 86 | ]; 87 | 88 | public function getFilamentAvatarUrl(): ?string 89 | { 90 | return $this->getFirstMediaUrl('avatar') ?? null; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /resources/js/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomatophp/filament-accounts/7f5f11765de2781e119f826163e9dcb7a8c1a347/resources/js/.gitkeep -------------------------------------------------------------------------------- /resources/lang/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomatophp/filament-accounts/7f5f11765de2781e119f826163e9dcb7a8c1a347/resources/lang/.gitkeep -------------------------------------------------------------------------------- /resources/lang/ar/messages.php: -------------------------------------------------------------------------------- 1 | 'الحسابات', 5 | 'accounts' => [ 6 | 'label' => 'الحسابات', 7 | 'single' => 'حساب', 8 | 'columns' => [ 9 | 'id' => 'المعرف', 10 | 'account' => 'الحساب', 11 | 'teams' => 'الفرق', 12 | 'avatar' => 'صورة الملف الشخصي', 13 | 'name' => 'الاسم', 14 | 'email' => 'البريد الالكتروني', 15 | 'phone' => 'الهاتف', 16 | 'type' => 'النوع', 17 | 'address' => 'العنوان', 18 | 'password' => 'كلمة المرور', 19 | 'password_confirmation' => 'تأكيد كلمة المرور', 20 | 'loginBy' => 'تسجيل الدخول بواسطة', 21 | 'is_active' => 'هل نشط؟', 22 | 'is_login' => 'يمكن تسجيل الدخول؟', 23 | 'created_at' => 'تم الإنشاء في', 24 | 'updated_at' => 'تم التحديث في', 25 | ], 26 | 'filters' => [ 27 | 'type' => 'حسب النوع', 28 | 'teams' => 'حسب الفريق', 29 | 'is_active' => 'هل هو مفعل؟', 30 | 'is_login' => 'هل يستطيع تسجيل الدخول؟', 31 | ], 32 | 'actions' => [ 33 | 'teams' => 'إدارة الفرق', 34 | 'impersonate' => 'تسجيل الدخول', 35 | 'password' => 'تغيير كلمة المرور', 36 | 'notifications' => 'إرسال الإشعارات', 37 | 'edit' => 'تعديل', 38 | 'delete' => 'حذف', 39 | 'force_delete' => 'حذف نهائي', 40 | 'restore' => 'استعادة', 41 | ], 42 | 'notifications' => [ 43 | 'use_notification_template' => 'استخدام قالب الإشعارات', 44 | 'template_id' => 'القالب', 45 | 'image' => 'الصورة', 46 | 'title' => 'العنوان', 47 | 'body' => 'النص', 48 | 'action' => 'العملية', 49 | 'url' => 'الرابط', 50 | 'icon' => 'الأيقونة', 51 | 'type' => 'النوع', 52 | 'providers' => 'ارسال عن طريق', 53 | ], 54 | 'export' => [ 55 | 'title' => 'تصدير', 56 | 'columns' => 'الأعمدة', 57 | ], 58 | 'import' => [ 59 | 'title' => 'استيراد', 60 | 'excel' => 'ملف اكسيل', 61 | 'hint' => 'يرجى تحميل ملف اكسيل لاستيراد الحسابات', 62 | 'success' => 'تم استيراد الحسابات بنجاح', 63 | 'body' => 'تم استيراد الحسابات بنجاح', 64 | 'error' => 'خطأ أثناء استيراد الحسابات', 65 | 'error-body' => 'حدث خطأ أثناء استيراد الحسابات', 66 | ], 67 | ], 68 | 'meta' => [ 69 | 'label' => 'المعلومات', 70 | 'single' => 'معلومة', 71 | 'create' => 'إضافة معلومة', 72 | 'columns' => [ 73 | 'account' => 'الحساب', 74 | 'key' => 'المفتاح', 75 | 'value' => 'القيمة', 76 | ], 77 | ], 78 | 'locations' => [ 79 | 'label' => 'المواقع', 80 | 'single' => 'موقع', 81 | 'create' => 'إضافة موقع', 82 | ], 83 | 'requests' => [ 84 | 'label' => 'طلبات الحساب', 85 | 'single' => 'طلب للحساب', 86 | 'columns' => [ 87 | 'account' => 'الحساب', 88 | 'user' => 'المستخدم', 89 | 'type' => 'النوع', 90 | 'status' => 'الحالة', 91 | 'is_approved' => 'هل تم الموافقة؟', 92 | 'is_approved_at' => 'تمت الموافقة في', 93 | ], 94 | ], 95 | 'contacts' => [ 96 | 'label' => 'اتصل بنا', 97 | 'single' => 'اتصال', 98 | 'columns' => [ 99 | 'type' => 'النوع', 100 | 'status' => 'الحالة', 101 | 'name' => 'الاسم', 102 | 'email' => 'البريد الالكتروني', 103 | 'phone' => 'الهاتف', 104 | 'subject' => 'الموضوع', 105 | 'active' => 'نشط', 106 | ], 107 | ], 108 | 'profile' => [ 109 | 'title' => 'تعديل الملف الشخصي', 110 | 'edit' => [ 111 | 'title' => 'تعديل المعلومات', 112 | 'description' => 'تحديث معلومات الملف الشخصي وعنوان البريد الإلكتروني الخاص بحسابك.', 113 | 'name' => 'الاسم', 114 | 'email' => 'البريد الإلكتروني', 115 | ], 116 | 'password' => [ 117 | 'title' => 'تغيير كلمة المرور', 118 | 'description' => 'تأكد من أن حسابك يستخدم كلمة مرور طويلة وعشوائية للبقاء آمنًا.', 119 | 'current_password' => 'كلمة المرور الحالية', 120 | 'new_password' => 'كلمة المرور الجديدة', 121 | 'confirm_password' => 'تأكيد كلمة المرور', 122 | ], 123 | 'browser' => [ 124 | 'sessions_last_active' => 'اخر جلسة', 125 | 'browser_section_title' => 'جلسات المتصفح', 126 | 'browser_section_description' => 'إدارة وتسجيل الخروج من جلساتك النشطة على المتصفحات والأجهزة الأخرى.', 127 | 'browser_sessions_log_out' => 'تسجيل الخروج من جلسات المتصفح الأخرى', 128 | 'browser_sessions_confirm_pass' => 'يرجى إدخال كلمة المرور لتأكيد رغبتك في تسجيل الخروج من جلسات المتصفح الأخرى عبر جميع أجهزتك.', 129 | 'password' => 'كلمة المرور', 130 | 'confirm' => 'تأكيد', 131 | 'nevermind' => 'لا بأس', 132 | 'browser_sessions_logout_notification' => 'تم تسجيل الخروج من جلسات المتصفح الخاصة بك.', 133 | 'browser_sessions_logout_failed_notification' => 'كلمة المرور غير صحيحة.', 134 | 'sessions_device' => 'الجهاز', 135 | 'sessions_content' => 'الأجهزة المتصلة', 136 | 'incorrect_password' => 'كلمة المرور التي أدخلتها غير صحيحة.', 137 | ], 138 | 'delete' => [ 139 | 'delete_account' => 'حذف الحساب', 140 | 'delete_account_description' => 'حذف حسابك بشكل دائم.', 141 | 'incorrect_password' => 'كلمة المرور التي أدخلتها غير صحيحة.', 142 | 'are_you_sure' => 'هل أنت متأكد من أنك تريد حذف حسابك؟ بمجرد حذف حسابك، سيتم حذف جميع موارده وبياناته بشكل دائم. يرجى إدخال كلمة المرور لتأكيد رغبتك في حذف حسابك نهائيًا.', 143 | 'yes_delete_it' => 'نعم، احذفه', 144 | 'password' => 'كلمة المرور', 145 | 'delete_account_card_description' => 'بمجرد حذف حسابك، سيتم حذف جميع موارده وبياناته بشكل دائم. قبل حذف حسابك، يرجى تنزيل أي بيانات أو معلومات ترغب في الاحتفاظ بها.', 146 | ], 147 | 'delete-team' => [ 148 | 'title' => 'حذف الفريق', 149 | 'description' => 'حذف فريقك بشكل دائم.', 150 | 'body' => 'بمجرد حذف الفريق، سيتم حذف جميع موارده وبياناته بشكل دائم. قبل حذف هذا الفريق، يرجى تنزيل أي بيانات أو معلومات ترغب في الاحتفاظ بها.', 151 | 'delete' => 'حذف الفريق', 152 | 'delete_account' => 'حذف الفريق', 153 | 'delete_account_description' => 'هل أنت متأكد من أنك تريد حذف فريقك؟ بمجرد حذف فريقك، سيتم حذف جميع موارده وبياناته بشكل دائم. يرجى إدخال كلمة المرور لتأكيد رغبتك في حذف فريقك نهائيًا.', 154 | 'yes_delete_it' => 'نعم، احذفه', 155 | 'password' => 'كلمة المرور', 156 | 'incorrect_password' => 'كلمة المرور التي أدخلتها غير صحيحة.', 157 | 'are_you_sure' => 'هل أنت متأكد من أنك تريد حذف فريقك؟ بمجرد حذف فريقك، سيتم حذف جميع موارده وبياناته بشكل دائم. يرجى إدخال كلمة المرور لتأكيد رغبتك في حذف فريقك نهائيًا.', 158 | ], 159 | 'token' => [ 160 | 'title' => 'رموز API', 161 | 'description' => 'تسمح رموز API للخدمات الخارجية بالمصادقة مع تطبيقنا نيابةً عنك.', 162 | 'name' => 'الاسم', 163 | 'created_at' => 'تم الإنشاء في', 164 | 'expires_at' => 'تنتهي في', 165 | 'abilities' => 'القدرات', 166 | 'action_label' => 'إنشاء رمز', 167 | 'create_notification' => 'تم إنشاء الرمز بنجاح!', 168 | 'modal_heading' => 'إنشاء رمز', 169 | 'empty_state_heading' => 'لا توجد رموز', 170 | 'empty_state_description' => 'إنشاء رمز جديد للمصادقة مع API.', 171 | 'delete_token' => 'حذف الرمز', 172 | 'delete_token_description' => 'هل أنت متأكد من أنك تريد حذف هذا الرمز؟', 173 | 'delete_token_confirmation' => 'نعم، احذفه', 174 | 'delete_token_notification' => 'تم حذف الرمز بنجاح!', 175 | 'modal_heading_2' => 'تم إنشاء الرمز بنجاح', 176 | 'helper_text' => 'يمكنك تعديل الرمز أدناه. تأكد من نسخه الآن، حيث لن تتمكن من رؤيته مرة أخرى.', 177 | 'token' => 'الرمز', 178 | ], 179 | ], 180 | 'teams' => [ 181 | 'title' => 'إعدادات الفريق', 182 | 'actions' => [ 183 | 'cancel_invitation' => 'إلغاء الدعوة', 184 | 'resend_invitation' => 'إعادة ارسال الدعوة', 185 | ], 186 | 'edit' => [ 187 | 'title' => 'تعديل إسم الفريق', 188 | 'description' => 'تحديث معلومات الفريق وصورة الفريقك.', 189 | 'name' => 'الاسم', 190 | 'email' => 'البريد الإلكتروني', 191 | 'avatar' => 'الصورة الرمزية', 192 | 'save' => 'حفظ', 193 | 'owner' => 'المالك', 194 | ], 195 | 'members' => [ 196 | 'title' => 'دعوة أعضاء الفريق', 197 | 'description' => 'إضافة عضو فريق جديد إلى فريقك، مما يسمح له بالتعاون معك.', 198 | 'team-members' => 'يرجى تقديم عنوان البريد الإلكتروني للشخص الذي ترغب في إضافته إلى هذا الفريق.', 199 | 'email' => 'البريد الإلكتروني', 200 | 'role' => 'الدور', 201 | 'send_invitation' => 'إرسال الدعوة', 202 | 'cancel' => 'إلغاء', 203 | 'not_in' => 'عنوان البريد الإلكتروني هو بالفعل عضو في الفريق.', 204 | 'required' => 'حقل البريد الإلكتروني مطلوب.', 205 | 'unique' => 'عنوان البريد الإلكتروني هو بالفعل عضو في الفريق.', 206 | 'role_required' => 'حقل الدور مطلوب.', 207 | 'notifications' => [ 208 | 'title' => 'دعوة عضو فريق', 209 | 'body' => 'لقد تمت دعوتك للانضمام إلى فريق :team.', 210 | 'accept' => 'قبول الدعوة', 211 | 'cancel' => 'إلغاء الدعوة', 212 | ], 213 | 'leave_team' => 'مغادرة الفريق', 214 | 'remove_member' => 'إزالة عضو', 215 | 'manage_role' => 'إدارة الدور', 216 | 'list' => [ 217 | 'title' => 'أعضاء الفريق', 218 | 'description' => 'جميع الأشخاص الذين هم جزء من هذا الفريق.', 219 | ], 220 | ], 221 | 'delete' => [ 222 | 'title' => 'حذف الفريق', 223 | 'description' => 'حذف فريقك بشكل دائم.', 224 | 'body' => 'بمجرد حذف فريق، سيتم حذف جميع موارده وبياناته بشكل دائم. قبل حذف هذا الفريق، يرجى تنزيل أي بيانات أو معلومات تتعلق بهذا الفريق التي ترغب في الاحتفاظ بها.', 225 | 'delete' => 'حذف الفريق', 226 | 'delete_account' => 'حذف الفريق', 227 | 'delete_account_description' => 'هل أنت متأكد أنك تريد حذف فريقك؟ بمجرد حذف فريقك، سيتم حذف جميع موارده وبياناته بشكل دائم. يرجى إدخال كلمة المرور الخاصة بك لتأكيد أنك ترغب في حذف فريقك بشكل دائم.', 228 | 'yes_delete_it' => 'نعم، احذفه', 229 | 'password' => 'كلمة المرور', 230 | 'incorrect_password' => 'كلمة المرور التي أدخلتها غير صحيحة.', 231 | 'are_you_sure' => 'هل أنت متأكد أنك تريد حذف فريقك؟ بمجرد حذف فريقك، سيتم حذف جميع موارده وبياناته بشكل دائم. يرجى إدخال كلمة المرور الخاصة بك لتأكيد أنك ترغب في حذف فريقك بشكل دائم.', 232 | ], 233 | ], 234 | 'team' => [ 235 | 'title' => 'الفرق', 236 | 'single' => 'فريق', 237 | 'columns' => [ 238 | 'avatar' => 'الشعار', 239 | 'name' => 'الاسم', 240 | 'owner' => 'المالك', 241 | 'personal_team' => 'فريق شخصي', 242 | ], 243 | ], 244 | 'roles' => [ 245 | 'admin' => [ 246 | 'name' => 'مدير النظام', 247 | 'description' => 'مدير النظام يمكنه إدارة النظام بالكامل.', 248 | ], 249 | 'user' => [ 250 | 'name' => 'مستخدم', 251 | 'description' => 'مستخدم عادي يمكنه القراءة والتحديث.', 252 | ], 253 | ], 254 | 'login' => [ 255 | 'active' => 'عفواً برجاء تاكيد الحساب اولاً ثم اعادة تسجيل الدخول', 256 | ], 257 | 258 | 'settings' => [ 259 | 'types' => [ 260 | 'title' => 'أنواع الحسابات', 261 | ], 262 | ], 263 | 264 | 'address' => [ 265 | 'title' => 'تعديل العناوين', 266 | ], 267 | 268 | 'account-requests' => [ 269 | 'title' => 'طلبات الحساب', 270 | 'status' => 'الحالة', 271 | 'types' => 'النوع', 272 | 'button' => 'تعديل الانواع والحالات', 273 | ], 274 | 275 | 'contact-us' => [ 276 | 'status' => 'تعديل حالات اتصل بنا', 277 | 'status-button' => 'إدارة الحالات', 278 | 'footer' => 'هل لديك اي مشكلة؟ او تحتاج الى مساعدة؟', 279 | 'modal' => 'برجاء مليء هذا النموذج للتواصل معانا', 280 | 'label' => 'تواصل معنا', 281 | 'form' => [ 282 | 'name' => 'الاسم', 283 | 'email' => 'البريد الالكتروني', 284 | 'phone' => 'الهاتف', 285 | 'subject' => 'الموضوع', 286 | 'message' => 'الرسالة', 287 | ], 288 | 'notification' => [ 289 | 'title' => 'عملية ناجحة', 290 | 'body' => 'تم ارسال الرسالة بنجاح', 291 | ], 292 | ], 293 | ]; 294 | -------------------------------------------------------------------------------- /resources/lang/en/messages.php: -------------------------------------------------------------------------------- 1 | 'Save', 5 | 'saved_successfully' => 'Saved Successfully', 6 | 'group' => 'Accounts', 7 | 'accounts' => [ 8 | 'label' => 'Accounts', 9 | 'single' => 'Account', 10 | 'columns' => [ 11 | 'id' => 'ID', 12 | 'avatar' => 'Avatar', 13 | 'account' => 'Account', 14 | 'teams' => 'Teams', 15 | 'name' => 'Name', 16 | 'email' => 'Email', 17 | 'phone' => 'Phone', 18 | 'type' => 'Type', 19 | 'address' => 'Address', 20 | 'password' => 'Password', 21 | 'password_confirmation' => 'Password Confirmation', 22 | 'loginBy' => 'Login By', 23 | 'is_active' => 'Is Active?', 24 | 'is_login' => 'Can Login?', 25 | 'created_at' => 'Created At', 26 | 'updated_at' => 'Updated At', 27 | ], 28 | 'filters' => [ 29 | 'type' => 'Type', 30 | 'teams' => 'Teams', 31 | 'is_active' => 'Is Active?', 32 | 'is_login' => 'Can Login?', 33 | ], 34 | 'actions' => [ 35 | 'teams' => 'Manage Teams', 36 | 'impersonate' => 'Login As', 37 | 'password' => 'Change Password', 38 | 'notifications' => 'Send Notifications', 39 | 'edit' => 'Edit', 40 | 'delete' => 'Delete', 41 | 'force_delete' => 'Force Delete', 42 | 'restore' => 'Restore', 43 | ], 44 | 'notifications' => [ 45 | 'use_notification_template' => 'Use Notification Template', 46 | 'template_id' => 'Template', 47 | 'image' => 'Image', 48 | 'title' => 'Title', 49 | 'body' => 'Body', 50 | 'action' => 'Action', 51 | 'url' => 'URL', 52 | 'icon' => 'Icon', 53 | 'type' => 'Type', 54 | 'providers' => 'Send By', 55 | ], 56 | 'export' => [ 57 | 'title' => 'Export', 58 | 'columns' => 'Columns', 59 | ], 60 | 'import' => [ 61 | 'title' => 'Import', 62 | 'excel' => 'Excel', 63 | 'hint' => 'You can upload the same style of exported file', 64 | 'success' => 'Success', 65 | 'body' => 'Accounts imported successfully', 66 | 'error' => 'Error', 67 | 'error-body' => 'Error while importing accounts', 68 | ], 69 | ], 70 | 'meta' => [ 71 | 'label' => 'Metas', 72 | 'single' => 'Meta', 73 | 'create' => 'Create Meta', 74 | 'columns' => [ 75 | 'account' => 'Account', 76 | 'key' => 'Key', 77 | 'value' => 'Value', 78 | ], 79 | ], 80 | 'locations' => [ 81 | 'label' => 'Locations', 82 | 'single' => 'Location', 83 | 'create' => 'Create Location', 84 | ], 85 | 'requests' => [ 86 | 'label' => 'Account Requests', 87 | 'single' => 'Account Request', 88 | 'columns' => [ 89 | 'account' => 'Account', 90 | 'user' => 'User', 91 | 'type' => 'Type', 92 | 'status' => 'Status', 93 | 'is_approved' => 'Is Approved?', 94 | 'is_approved_at' => 'Is Approved At', 95 | ], 96 | ], 97 | 'contacts' => [ 98 | 'label' => 'Contacts', 99 | 'single' => 'Contact', 100 | 'columns' => [ 101 | 'type' => 'Type', 102 | 'status' => 'Status', 103 | 'name' => 'Name', 104 | 'email' => 'Email', 105 | 'phone' => 'Phone', 106 | 'subject' => 'Subject', 107 | 'message' => 'Message', 108 | 'active' => 'Active', 109 | ], 110 | ], 111 | 'profile' => [ 112 | 'title' => 'Edit Profile', 113 | 'edit' => [ 114 | 'title' => 'Edit Information', 115 | 'description' => "Update your account's profile information and email address.", 116 | 'name' => 'Name', 117 | 'email' => 'Email', 118 | ], 119 | 'password' => [ 120 | 'title' => 'Change Password', 121 | 'description' => 'Ensure your account is using a long, random password to stay secure.', 122 | 'current_password' => 'Current Password', 123 | 'new_password' => 'New Password', 124 | 'confirm_password' => 'Confirm Password', 125 | ], 126 | 'browser' => [ 127 | 'sessions_last_active' => 'Last Active', 128 | 'browser_section_title' => 'Browser Sessions', 129 | 'browser_section_description' => 'Manage and log out your active sessions on other browsers and devices.', 130 | 'browser_sessions_log_out' => 'Log Out Other Browser Sessions', 131 | 'browser_sessions_confirm_pass' => 'Please enter your password to confirm you would like to log out of your other browser sessions across all of your devices.', 132 | 'password' => 'Password', 133 | 'confirm' => 'Confirm', 134 | 'nevermind' => 'Nevermind', 135 | 'browser_sessions_logout_notification' => 'Your browser sessions have been logged out.', 136 | 'browser_sessions_logout_failed_notification' => 'Your password was incorrect.', 137 | 'sessions_device' => 'Device', 138 | 'sessions_content' => 'Connected Devices', 139 | 'incorrect_password' => 'The password you entered was incorrect.', 140 | ], 141 | 'delete' => [ 142 | 'delete_account' => 'Delete Account', 143 | 'delete_account_description' => 'Permanently delete your account.', 144 | 'incorrect_password' => 'The password you entered was incorrect.', 145 | 'are_you_sure' => 'Are you sure you want to delete your account? Once your account is deleted, all of its resources and data will be permanently deleted. Please enter your password to confirm you would like to permanently delete your account.', 146 | 'yes_delete_it' => 'Yes, delete it', 147 | 'password' => 'Password', 148 | 'delete_account_card_description' => 'Once your account is deleted, all of its resources and data will be permanently deleted. Before deleting your account, please download any data or information that you wish to retain.', 149 | ], 150 | 'delete-team' => [ 151 | 'title' => 'Delete Team', 152 | 'description' => 'Permanently delete your team.', 153 | 'body' => 'Once a team is deleted, all of its resources and data will be permanently deleted. Before deleting this team, please download any data or information regarding this team that you wish to retain.', 154 | 'delete' => 'Delete Team', 155 | 'delete_account' => 'Delete Team', 156 | 'delete_account_description' => 'Are you sure you want to delete your team? Once your team is deleted, all of its resources and data will be permanently deleted. Please enter your password to confirm you would like to permanently delete your team.', 157 | 'yes_delete_it' => 'Yes, delete it', 158 | 'password' => 'Password', 159 | 'incorrect_password' => 'The password you entered was incorrect.', 160 | 'are_you_sure' => 'Are you sure you want to delete your team? Once your team is deleted, all of its resources and data will be permanently deleted. Please enter your password to confirm you would like to permanently delete your team.', 161 | ], 162 | 'token' => [ 163 | 'title' => 'API Tokens', 164 | 'description' => 'API tokens allow third-party services to authenticate with our application on your behalf.', 165 | 'name' => 'Name', 166 | 'created_at' => 'Created At', 167 | 'expires_at' => 'Expires At', 168 | 'abilities' => 'Abilities', 169 | 'action_label' => 'Create Token', 170 | 'create_notification' => 'Token created successfully!', 171 | 'modal_heading' => 'Create Token', 172 | 'empty_state_heading' => 'No tokens', 173 | 'empty_state_description' => 'Create a new token to authenticate with the API.', 174 | 'delete_token' => 'Delete Token', 175 | 'delete_token_description' => 'Are you sure you would like to delete this token?', 176 | 'delete_token_confirmation' => 'Yes, delete it', 177 | 'delete_token_notification' => 'Token deleted successfully!', 178 | 'modal_heading_2' => 'Token Generated Successfully', 179 | 'helper_text' => "You may edit the token below. Make sure to copy it now, as you won't be able to see it again.", 180 | 'token' => 'Token', 181 | ], 182 | ], 183 | 'teams' => [ 184 | 'title' => 'Team Settings', 185 | 'actions' => [ 186 | 'cancel_invitation' => 'Cancel Invitation', 187 | 'resend_invitation' => 'Resend Invitation', 188 | ], 189 | 'edit' => [ 190 | 'title' => 'Edit Team Name', 191 | 'description' => "Update your team's profile information and email address.", 192 | 'name' => 'Name', 193 | 'email' => 'Email', 194 | 'avatar' => 'Avatar', 195 | 'save' => 'Save', 196 | 'owner' => 'Owner', 197 | ], 198 | 'members' => [ 199 | 'title' => 'Invite Team Members', 200 | 'description' => 'Add a new team member to your team, allowing them to collaborate with you.', 201 | 'team-members' => 'Please provide the email address of the person you would like to add to this team.', 202 | 'email' => 'Email', 203 | 'role' => 'Role', 204 | 'send_invitation' => 'Send Invitation', 205 | 'cancel' => 'Cancel', 206 | 'not_in' => 'The email address is already a team member.', 207 | 'required' => 'The email field is required.', 208 | 'unique' => 'The email address is already a team member.', 209 | 'role_required' => 'The role field is required.', 210 | 'notifications' => [ 211 | 'title' => 'Team Member Invitation', 212 | 'body' => 'You have been invited to join the :team team.', 213 | 'accept' => 'Accept Invitation', 214 | 'cancel' => 'Cancel Invitation', 215 | ], 216 | 'leave_team' => 'Leave Team', 217 | 'remove_member' => 'Remove Member', 218 | 'manage_role' => 'Manage Role', 219 | 'list' => [ 220 | 'title' => 'Team Members', 221 | 'description' => 'All of the people that are part of this team.', 222 | ], 223 | ], 224 | 'delete' => [ 225 | 'title' => 'Delete Team', 226 | 'description' => 'Permanently delete your team.', 227 | 'body' => 'Once a team is deleted, all of its resources and data will be permanently deleted. Before deleting this team, please download any data or information regarding this team that you wish to retain.', 228 | 'delete' => 'Delete Team', 229 | 'delete_account' => 'Delete Team', 230 | 'delete_account_description' => 'Are you sure you want to delete your team? Once your team is deleted, all of its resources and data will be permanently deleted. Please enter your password to confirm you would like to permanently delete your team.', 231 | 'yes_delete_it' => 'Yes, delete it', 232 | 'password' => 'Password', 233 | 'incorrect_password' => 'The password you entered was incorrect.', 234 | 'are_you_sure' => 'Are you sure you want to delete your team? Once your team is deleted, all of its resources and data will be permanently deleted. Please enter your password to confirm you would like to permanently delete your team.', 235 | ], 236 | ], 237 | 'team' => [ 238 | 'title' => 'Teams', 239 | 'single' => 'Team', 240 | 'columns' => [ 241 | 'avatar' => 'Avatar', 242 | 'name' => 'Name', 243 | 'owner' => 'Owner', 244 | 'personal_team' => 'Personal Team', 245 | ], 246 | ], 247 | 248 | 'roles' => [ 249 | 'admin' => [ 250 | 'name' => 'Administrator', 251 | 'description' => 'Administrator users can perform any action.', 252 | ], 253 | 'user' => [ 254 | 'name' => 'User', 255 | 'description' => 'User users can read and update data.', 256 | ], 257 | ], 258 | 'login' => [ 259 | 'active' => 'Please Verify Your Account First, than try to login again', 260 | ], 261 | 262 | 'settings' => [ 263 | 'types' => [ 264 | 'title' => 'Accounts Types', 265 | ], 266 | ], 267 | 268 | 'address' => [ 269 | 'title' => 'Edit Locations', 270 | ], 271 | 272 | 'account-requests' => [ 273 | 'title' => 'Requests', 274 | 'status' => 'Request Status', 275 | 'types' => 'Request Types', 276 | 'button' => 'Manage Types & Status', 277 | ], 278 | 279 | 'contact-us' => [ 280 | 'status' => 'Edit Contact Us Status', 281 | 'status-button' => 'Manage Status', 282 | 'footer' => 'Do you have any problems or questions? Please', 283 | 'modal' => 'Please Fill This Form To Contact Us', 284 | 'label' => 'Contact Us', 285 | 'form' => [ 286 | 'name' => 'Name', 287 | 'email' => 'Email', 288 | 'phone' => 'Phone', 289 | 'subject' => 'Subject', 290 | 'message' => 'Message', 291 | ], 292 | 'notification' => [ 293 | 'title' => 'Contact Us', 294 | 'body' => 'Your message has been sent successfully', 295 | ], 296 | ], 297 | ]; 298 | -------------------------------------------------------------------------------- /resources/views/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomatophp/filament-accounts/7f5f11765de2781e119f826163e9dcb7a8c1a347/resources/views/.gitkeep -------------------------------------------------------------------------------- /resources/views/components/account-column.blade.php: -------------------------------------------------------------------------------- 1 | @php 2 | $account = config('filament-accounts.model')::withTrashed()->find($getState()); 3 | $tenent = \Filament\Facades\Filament::getTenant()?->id; 4 | $panel = \Filament\Facades\Filament::getCurrentPanel()->getId() ?? null; 5 | if(isset(\TomatoPHP\FilamentAccounts\Filament\Resources\AccountResource::getPages()['edit'])){ 6 | $url = \TomatoPHP\FilamentAccounts\Filament\Resources\AccountResource::getUrl('edit', ['record' => $account, 'tenant' => $tenent]); 7 | } 8 | else { 9 | $url = null; 10 | } 11 | 12 | @endphp 13 | 14 | @if($account) 15 | @if($url) 16 | 17 |
18 | 22 |
23 |
24 |
25 | {{ $account->name }} 26 |
27 |
28 | {{ $account->loginBy === 'email' ? $account->email : $account->phone }} 29 |
30 |
31 |
32 | @else 33 |
34 |
35 | 39 |
40 |
41 |
42 | {{ $account->name }} 43 |
44 |
45 | {{ $account->loginBy === 'email' ? $account->email : $account->phone }} 46 |
47 |
48 |
49 | @endif 50 | @endif 51 | -------------------------------------------------------------------------------- /src/Components/AccountColumn.php: -------------------------------------------------------------------------------- 1 | avatar = $avatar; 16 | 17 | return $this; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Console/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomatophp/filament-accounts/7f5f11765de2781e119f826163e9dcb7a8c1a347/src/Console/.gitkeep -------------------------------------------------------------------------------- /src/Console/FilamentAccountsInstall.php: -------------------------------------------------------------------------------- 1 | info('Publish Vendor Assets'); 40 | $this->callSilent('optimize:clear'); 41 | $this->artisanCommand(['migrate']); 42 | $this->artisanCommand(['optimize:clear']); 43 | if (config('filament-accounts.features.types') && class_exists(\TomatoPHP\FilamentTypes\Models\Type::class)) { 44 | $typesArray = [ 45 | [ 46 | 'name' => [ 47 | 'ar' => 'عميل', 48 | 'en' => 'Customer', 49 | ], 50 | 'key' => 'customer', 51 | 'for' => 'accounts', 52 | 'type' => 'type', 53 | 'icon' => 'heroicon-c-user-group', 54 | 'color' => '#d91919', 55 | ], 56 | [ 57 | 'name' => [ 58 | 'ar' => 'حساب', 59 | 'en' => 'Account', 60 | ], 61 | 'key' => 'account', 62 | 'for' => 'accounts', 63 | 'type' => 'type', 64 | 'icon' => 'heroicon-c-user-circle', 65 | 'color' => '#0a56d9', 66 | ], 67 | [ 68 | 'name' => [ 69 | 'ar' => 'تحت المراجعة', 70 | 'en' => 'Pending', 71 | ], 72 | 'key' => 'pending', 73 | 'for' => 'contacts', 74 | 'type' => 'status', 75 | 'icon' => 'heroicon-c-pause-circle', 76 | 'color' => '#ffcf00', 77 | ], 78 | [ 79 | 'name' => [ 80 | 'ar' => 'جاري المتابعة', 81 | 'en' => 'Active', 82 | ], 83 | 'key' => 'active', 84 | 'for' => 'contacts', 85 | 'type' => 'status', 86 | 'icon' => 'heroicon-c-play-circle', 87 | 'color' => '#1897ff', 88 | ], 89 | [ 90 | 'name' => [ 91 | 'ar' => 'تم اغلاقها', 92 | 'en' => 'Closed', 93 | ], 94 | 'key' => 'closed', 95 | 'for' => 'contacts', 96 | 'type' => 'status', 97 | 'icon' => 'heroicon-c-check-circle', 98 | 'color' => '#38fc34', 99 | ], 100 | [ 101 | 'name' => [ 102 | 'ar' => 'الموافقة علي الحساب', 103 | 'en' => 'Account Approve', 104 | ], 105 | 'key' => 'account_approve', 106 | 'for' => 'contacts', 107 | 'type' => 'type', 108 | 'icon' => 'heroicon-c-check-circle', 109 | 'color' => '#38fc34', 110 | ], 111 | ]; 112 | foreach ($typesArray as $item) { 113 | $checkFirst = Type::query()->where('key', $item['key'])->first(); 114 | if (! $checkFirst) { 115 | Type::query()->create($item); 116 | } 117 | } 118 | } 119 | 120 | $this->info('Filament Accounts installed successfully.'); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/Export/ExportAccounts.php: -------------------------------------------------------------------------------- 1 | data['columns']); 18 | } 19 | 20 | public function collection() 21 | { 22 | $select = array_keys(collect($this->data['columns'])->filter(fn ($item, $key) => ! str($key)->contains('.'))->toArray()); 23 | 24 | return config('filament-accounts.model')::query() 25 | ->select($select) 26 | ->get() 27 | ->map(function ($item) { 28 | return collect($this->data['columns'])->map(function ($column, $key) use ($item) { 29 | if (str($key)->contains('.')) { 30 | $keys = explode('.', $key); 31 | if (is_a($item->{$keys[0]}, Collection::class)) { 32 | return collect($item->{$keys[0]})->map(fn ($item) => $item->{$keys[1]})->implode(', '); 33 | } else { 34 | return $item->{$keys[0]}?->{$keys[1]}; 35 | } 36 | 37 | } 38 | 39 | return $item->{$key}; 40 | }); 41 | }); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Facades/FilamentAccounts.php: -------------------------------------------------------------------------------- 1 | Pages\ManageAccounts::route('/'), 74 | ] : [ 75 | 'index' => Pages\ListAccounts::route('/'), 76 | 'create' => Pages\CreateAccount::route('/create'), 77 | 'edit' => Pages\EditAccount::route('/{record}/edit'), 78 | 'view' => Pages\ViewAccount::route('/{record}'), 79 | ]; 80 | } 81 | 82 | public static function getEloquentQuery(): Builder 83 | { 84 | return parent::getEloquentQuery() 85 | ->withoutGlobalScopes([ 86 | SoftDeletingScope::class, 87 | ]); 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Actions/Components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomatophp/filament-accounts/7f5f11765de2781e119f826163e9dcb7a8c1a347/src/Filament/Resources/AccountResource/Actions/Components/.gitkeep -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Actions/Components/Action.php: -------------------------------------------------------------------------------- 1 | using(function (array $data) { 13 | if (isset($data['password'])) { 14 | $data['password'] = bcrypt($data['password']); 15 | } 16 | if (isset($data['loginBy']) && $data['loginBy'] === 'email' && ! empty($data['email'])) { 17 | $data['username'] = $data['email']; 18 | } elseif (isset($data['loginBy']) && $data['loginBy'] === 'phone' && ! empty($data['phone'])) { 19 | $data['username'] = $data['phone']; 20 | } else { 21 | $data['username'] = str($data['name'])->slug()->toString(); 22 | } 23 | 24 | return config('filament-accounts.model')::query()->create($data); 25 | }); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Actions/Components/DeleteAction.php: -------------------------------------------------------------------------------- 1 | icon('heroicon-s-cog') 14 | ->tooltip('Accounts Types') 15 | ->label('Accounts Types') 16 | ->hiddenLabel() 17 | ->url(AccountTypes::getUrl()); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Actions/Components/ViewAction.php: -------------------------------------------------------------------------------- 1 | getActions(); 25 | } 26 | 27 | public function getActions(): array 28 | { 29 | return collect($this->getDefaultActions())->merge(self::$actions)->map(function (StaticAction $action) { 30 | if (method_exists($action, 'record') && str($action->getName())->contains(['create', 'edit', 'view', 'impersonate'])) { 31 | $action->record(method_exists(self::$page, 'getRecord') ? self::$page->getRecord() : null) 32 | ->model(method_exists(self::$page, 'getModel') ? self::$page->getModel() : null) 33 | ->modelLabel(method_exists(self::$page, 'getModelLabel') ? get_model_label(self::$page->getModel()) : null) 34 | ->form(fn (Form $form) => app(self::$page->getResource())::form($form)) 35 | ->url(fn () => isset(app(self::$page->getResource())::getPages()[$action->getName()]) ? app(app(self::$page->getResource())::getPages()[$action->getName()]->getPage())->getUrl(['record' => method_exists(self::$page, 'getRecord') ? self::$page->getRecord() : null]) : null); 36 | } 37 | 38 | return $action; 39 | })->toArray(); 40 | } 41 | 42 | public static function register(StaticAction | array | \Closure $component): void 43 | { 44 | if (is_array($component)) { 45 | foreach ($component as $item) { 46 | if ($item instanceof StaticAction) { 47 | self::$actions[] = $item; 48 | } 49 | } 50 | } elseif ($component instanceof \Closure) { 51 | self::$actions[] = (new self)->evaluate($component); 52 | } else { 53 | self::$actions[] = $component; 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Actions/CreatePageActions.php: -------------------------------------------------------------------------------- 1 | schema(self::getSchema())->columns(2); 15 | } 16 | 17 | public static function getDefaultComponents(): array 18 | { 19 | return [ 20 | Components\Name::make(), 21 | Components\Email::make(), 22 | Components\Phone::make(), 23 | ]; 24 | } 25 | 26 | private static function getSchema(): array 27 | { 28 | return array_merge(self::getDefaultComponents(), self::$schema); 29 | } 30 | 31 | public static function register(Field | array $component): void 32 | { 33 | if (is_array($component)) { 34 | foreach ($component as $item) { 35 | if ($item instanceof Field) { 36 | self::$schema[] = $item; 37 | } 38 | } 39 | 40 | } else { 41 | self::$schema[] = $component; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Form/Components/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomatophp/filament-accounts/7f5f11765de2781e119f826163e9dcb7a8c1a347/src/Filament/Resources/AccountResource/Form/Components/.gitkeep -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Form/Components/Address.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.columns.address')) 13 | ->columnSpanFull(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Form/Components/Avatar.php: -------------------------------------------------------------------------------- 1 | alignCenter() 13 | ->collection('avatar') 14 | ->columnSpan(2) 15 | ->label(trans('filament-accounts::messages.accounts.columns.avatar')); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Form/Components/Component.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.columns.email')) 13 | ->required(fn (Forms\Get $get) => $get('loginBy') === 'email') 14 | ->email() 15 | ->maxLength(255); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Form/Components/IsActive.php: -------------------------------------------------------------------------------- 1 | columnSpan(2) 13 | ->label(trans('filament-accounts::messages.accounts.columns.is_active')) 14 | ->default(false) 15 | ->required(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Form/Components/IsLogin.php: -------------------------------------------------------------------------------- 1 | default(false) 12 | ->columnSpan(2) 13 | ->label(trans('filament-accounts::messages.accounts.columns.is_login')) 14 | ->live(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Form/Components/LoginBy.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.columns.loginBy')) 13 | ->searchable() 14 | ->options([ 15 | 'email' => trans('filament-accounts::messages.accounts.columns.email'), 16 | 'phone' => trans('filament-accounts::messages.accounts.columns.phone'), 17 | ]) 18 | ->required() 19 | ->default('email'); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Form/Components/Name.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.columns.name')) 13 | ->columnSpan(2) 14 | ->required() 15 | ->maxLength(255); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Form/Components/Password.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.columns.password')) 13 | ->confirmed() 14 | ->visible(fn (Forms\Get $get) => $get('is_login')) 15 | ->password() 16 | ->dehydrateStateUsing(fn ($state) => bcrypt($state)) 17 | ->maxLength(255); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Form/Components/PasswordConfirmation.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.columns.password_confirmation')) 13 | ->visible(fn (Forms\Get $get) => $get('is_login')) 14 | ->password() 15 | ->maxLength(255); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Form/Components/Phone.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.columns.phone')) 13 | ->required(fn (Forms\Get $get) => $get('loginBy') === 'phone') 14 | ->tel() 15 | ->maxLength(255); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Form/Components/Type.php: -------------------------------------------------------------------------------- 1 | columnSpanFull() 14 | ->label(trans('filament-accounts::messages.accounts.columns.type')) 15 | ->searchable() 16 | ->required() 17 | ->options(\TomatoPHP\FilamentTypes\Models\Type::query()->where('for', 'accounts')->where('type', 'type')->pluck('name', 'key')->toArray()) 18 | ->default('account'); 19 | } else { 20 | return Forms\Components\TextInput::make('type') 21 | ->columnSpanFull() 22 | ->label(trans('filament-accounts::messages.accounts.columns.type')) 23 | ->required() 24 | ->default('account'); 25 | } 26 | 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/InfoList/AccountInfoList.php: -------------------------------------------------------------------------------- 1 | schema(self::getSchema())->columns(2); 15 | } 16 | 17 | public static function getDefaultComponents(): array 18 | { 19 | return [ 20 | Entries\Name::make(), 21 | Entries\Email::make(), 22 | Entries\Phone::make(), 23 | ]; 24 | } 25 | 26 | private static function getSchema(): array 27 | { 28 | return array_merge(self::getDefaultComponents(), self::$schema); 29 | } 30 | 31 | public static function register(Entry | array $component): void 32 | { 33 | if (is_array($component)) { 34 | foreach ($component as $item) { 35 | if ($item instanceof Entry) { 36 | self::$schema[] = $item; 37 | } 38 | } 39 | 40 | } else { 41 | self::$schema[] = $component; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/InfoList/Entries/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomatophp/filament-accounts/7f5f11765de2781e119f826163e9dcb7a8c1a347/src/Filament/Resources/AccountResource/InfoList/Entries/.gitkeep -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/InfoList/Entries/Address.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.columns.address')) 13 | ->columnSpanFull(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/InfoList/Entries/Avatar.php: -------------------------------------------------------------------------------- 1 | alignCenter() 13 | ->collection('avatar') 14 | ->columnSpan(2) 15 | ->columnSpanFull() 16 | ->label(trans('filament-accounts::messages.accounts.columns.avatar')); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/InfoList/Entries/Email.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.columns.email')); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/InfoList/Entries/Entry.php: -------------------------------------------------------------------------------- 1 | columnSpan(2) 13 | ->label(trans('filament-accounts::messages.accounts.columns.is_active')) 14 | ->boolean(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/InfoList/Entries/IsLogin.php: -------------------------------------------------------------------------------- 1 | default(false) 12 | ->columnSpan(2) 13 | ->label(trans('filament-accounts::messages.accounts.columns.is_login')) 14 | ->boolean(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/InfoList/Entries/LoginBy.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.columns.loginBy')); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/InfoList/Entries/Name.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.columns.name')) 13 | ->columnSpan(2); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/InfoList/Entries/Phone.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.columns.phone')); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/InfoList/Entries/Type.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.columns.type')); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Pages/AccountTypes.php: -------------------------------------------------------------------------------- 1 | $parameters 13 | */ 14 | public static function getUrl(array $parameters = [], bool $isAbsolute = true, ?string $panel = null, ?Model $tenant = null): string 15 | { 16 | if (blank($panel) || Filament::getPanel($panel)->hasTenancy()) { 17 | $parameters['tenant'] ??= ($tenant ?? Filament::getTenant()); 18 | } 19 | 20 | return route(static::getRouteName($panel), $parameters, $isAbsolute); 21 | } 22 | 23 | public function getTitle(): string 24 | { 25 | return trans('filament-accounts::messages.settings.types.title'); 26 | } 27 | 28 | public function getType(): string 29 | { 30 | return 'type'; 31 | } 32 | 33 | public function getFor(): string 34 | { 35 | return 'accounts'; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Pages/CreateAccount.php: -------------------------------------------------------------------------------- 1 | slug()->toString(); 23 | } 24 | 25 | return $data; 26 | } 27 | 28 | protected function getHeaderActions(): array 29 | { 30 | return config('filament-accounts.resource.pages.create') ? config('filament-accounts.resource.pages.create')::make($this) : AccountResource\Actions\CreatePageActions::make($this); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Pages/EditAccount.php: -------------------------------------------------------------------------------- 1 | deferLoading() 16 | ->bulkActions(config('filament-accounts.resource.table.bulkActions') ? config('filament-accounts.resource.table.bulkActions')::make() : AccountBulkActions::make()) 17 | ->actions(config('filament-accounts.resource.table.actions') ? config('filament-accounts.resource.table.actions')::make() : AccountActions::make()) 18 | ->filters(config('filament-accounts.resource.table.filters') ? config('filament-accounts.resource.table.filters')::make() : AccountFilters::make()) 19 | ->headerActions(config('filament-accounts.resource.table.headerActions') ? config('filament-accounts.resource.table.headerActions')::make() : AccountHeaderActions::make()) 20 | ->defaultSort('id', 'desc') 21 | ->columns(self::getColumns()); 22 | } 23 | 24 | public static function getDefaultColumns(): array 25 | { 26 | return [ 27 | Columns\Id::make(), 28 | Columns\Name::make(), 29 | Columns\Email::make(), 30 | Columns\Phone::make(), 31 | Columns\CreatedAt::make(), 32 | Columns\UpdatedAt::make(), 33 | ]; 34 | } 35 | 36 | private static function getColumns(): array 37 | { 38 | return array_merge(self::getDefaultColumns(), self::$columns); 39 | } 40 | 41 | public static function register(Column | array $column): void 42 | { 43 | if (is_array($column)) { 44 | foreach ($column as $item) { 45 | if ($item instanceof Column) { 46 | self::$columns[] = $item; 47 | } 48 | } 49 | } else { 50 | self::$columns[] = $column; 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Table/Actions/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomatophp/filament-accounts/7f5f11765de2781e119f826163e9dcb7a8c1a347/src/Filament/Resources/AccountResource/Table/Actions/.gitkeep -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Table/Actions/Action.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.actions.password')) 14 | ->icon('heroicon-s-lock-closed') 15 | ->iconButton() 16 | ->tooltip(trans('filament-accounts::messages.accounts.actions.password')) 17 | ->color('danger') 18 | ->form([ 19 | Forms\Components\TextInput::make('password') 20 | ->label(trans('filament-accounts::messages.accounts.columns.password')) 21 | ->password() 22 | ->required() 23 | ->confirmed() 24 | ->maxLength(255), 25 | Forms\Components\TextInput::make('password_confirmation') 26 | ->label(trans('filament-accounts::messages.accounts.columns.password_confirmation')) 27 | ->password() 28 | ->required() 29 | ->maxLength(255), 30 | ]) 31 | ->action(function (array $data, $record) { 32 | $record->password = bcrypt($data['password']); 33 | $record->save(); 34 | 35 | Notification::make() 36 | ->title('Account Password Changed') 37 | ->body('Account password changed successfully') 38 | ->success() 39 | ->send(); 40 | }); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Table/Actions/DeleteAction.php: -------------------------------------------------------------------------------- 1 | iconButton() 13 | ->tooltip(__('filament-actions::delete.single.label')); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Table/Actions/EditAction.php: -------------------------------------------------------------------------------- 1 | iconButton() 13 | ->tooltip(__('filament-actions::edit.single.label')); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Table/Actions/ImpersonateAction.php: -------------------------------------------------------------------------------- 1 | guard('accounts') 14 | ->color('info') 15 | ->tooltip(trans('filament-accounts::messages.accounts.actions.impersonate')) 16 | ->redirectTo(config('filament-accounts.features.impersonate.redirect')); 17 | } else { 18 | return \Filament\Tables\Actions\Action::make('impersonate'); 19 | } 20 | 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Table/Actions/ViewAction.php: -------------------------------------------------------------------------------- 1 | iconButton() 13 | ->tooltip(__('filament-actions::view.single.label')); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Table/BulkActions/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomatophp/filament-accounts/7f5f11765de2781e119f826163e9dcb7a8c1a347/src/Filament/Resources/AccountResource/Table/BulkActions/.gitkeep -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Table/BulkActions/Action.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.columns.account')) 14 | ->toggleable() 15 | ->sortable(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Table/Columns/Column.php: -------------------------------------------------------------------------------- 1 | dateTime() 13 | ->description(fn ($record) => $record->created_at->diffForHumans()) 14 | ->toggleable(isToggledHiddenByDefault: true) 15 | ->sortable(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Table/Columns/Email.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.columns.email')) 13 | ->toggleable(isToggledHiddenByDefault: filament('filament-accounts')->useAvatar) 14 | ->sortable() 15 | ->searchable(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Table/Columns/Id.php: -------------------------------------------------------------------------------- 1 | sortable(); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Table/Columns/IsActive.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.columns.is_active')) 13 | ->toggleable(isToggledHiddenByDefault: true) 14 | ->sortable() 15 | ->boolean(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Table/Columns/IsLogin.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.columns.is_login')) 13 | ->toggleable(isToggledHiddenByDefault: true) 14 | ->sortable() 15 | ->boolean(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Table/Columns/Name.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.columns.name')) 13 | ->toggleable(isToggledHiddenByDefault: filament('filament-accounts')->useAvatar) 14 | ->sortable() 15 | ->searchable(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Table/Columns/Phone.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.columns.phone')) 13 | ->toggleable(isToggledHiddenByDefault: filament('filament-accounts')->useAvatar) 14 | ->sortable() 15 | ->searchable(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Table/Columns/Type.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.columns.type')) 14 | ->toggleable() 15 | ->sortable() 16 | ->searchable(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Table/Columns/UpdatedAt.php: -------------------------------------------------------------------------------- 1 | dateTime() 13 | ->description(fn ($record) => $record->updated_at->diffForHumans()) 14 | ->toggleable(isToggledHiddenByDefault: true) 15 | ->sortable(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Table/Filters/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomatophp/filament-accounts/7f5f11765de2781e119f826163e9dcb7a8c1a347/src/Filament/Resources/AccountResource/Table/Filters/.gitkeep -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Table/Filters/Filter.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.filters.is_active')); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Table/Filters/IsLogin.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.filters.is_login')); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Table/Filters/Trashed.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.filters.type')) 11 | ->searchable() 12 | ->preload() 13 | ->options(\TomatoPHP\FilamentTypes\Models\Type::query()->where('for', 'accounts')->where('type', 'type')->pluck('name', 'key')->toArray()); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Table/HeaderActions/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomatophp/filament-accounts/7f5f11765de2781e119f826163e9dcb7a8c1a347/src/Filament/Resources/AccountResource/Table/HeaderActions/.gitkeep -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Table/HeaderActions/Action.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.export.title')) 15 | ->requiresConfirmation() 16 | ->color('info') 17 | ->icon('heroicon-o-arrow-down-on-square') 18 | ->fillForm([ 19 | 'columns' => [ 20 | 'id' => trans('filament-accounts::messages.accounts.columns.id'), 21 | 'name' => trans('filament-accounts::messages.accounts.columns.name'), 22 | 'email' => trans('filament-accounts::messages.accounts.columns.email'), 23 | 'phone' => trans('filament-accounts::messages.accounts.columns.phone'), 24 | 'address' => trans('filament-accounts::messages.accounts.columns.address'), 25 | 'type' => trans('filament-accounts::messages.accounts.columns.type'), 26 | 'is_login' => trans('filament-accounts::messages.accounts.columns.is_login'), 27 | 'is_active' => trans('filament-accounts::messages.accounts.columns.is_active'), 28 | 'created_at' => trans('filament-accounts::messages.accounts.columns.created_at'), 29 | 'updated_at' => trans('filament-accounts::messages.accounts.columns.updated_at'), 30 | ], 31 | ]) 32 | ->form([ 33 | Forms\Components\KeyValue::make('columns') 34 | ->label(trans('filament-accounts::messages.accounts.export.columns')) 35 | ->required() 36 | ->editableKeys(false) 37 | ->addable(false), 38 | ]) 39 | ->action(function (array $data) { 40 | return Excel::download(new ExportAccounts($data), 'accounts.csv'); 41 | }); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Filament/Resources/AccountResource/Table/HeaderActions/ImportAction.php: -------------------------------------------------------------------------------- 1 | label(trans('filament-accounts::messages.accounts.import.title')) 16 | ->form([ 17 | Forms\Components\FileUpload::make('excel') 18 | ->hint(trans('filament-accounts::messages.accounts.import.hint')) 19 | ->label(trans('filament-accounts::messages.accounts.import.excel')) 20 | ->acceptedFileTypes(['text/csv', 'application/vnd.ms-excel']) 21 | ->required(), 22 | ]) 23 | ->action(function (array $data) { 24 | try { 25 | Excel::import(new ImportAccounts, storage_path('app/public/' . $data['excel'])); 26 | 27 | Notification::make() 28 | ->title(trans('filament-accounts::messages.accounts.import.success')) 29 | ->body(trans('filament-accounts::messages.accounts.import.body')) 30 | ->success() 31 | ->send(); 32 | } catch (\Exception $e) { 33 | Notification::make() 34 | ->title(trans('filament-accounts::messages.accounts.import.error')) 35 | ->body(trans('filament-accounts::messages.accounts.import.error-body')) 36 | ->danger() 37 | ->send(); 38 | } 39 | 40 | }) 41 | ->color('warning') 42 | ->icon('heroicon-o-arrow-up-on-square'); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/FilamentAccountsPlugin.php: -------------------------------------------------------------------------------- 1 | useTypes) { 56 | $panel->pages([ 57 | AccountResource\Pages\AccountTypes::class, 58 | ]); 59 | } 60 | 61 | if ($this->useResource) { 62 | $panel->resources($resources); 63 | } 64 | 65 | } 66 | 67 | public function useExport(bool $useExport = true): static 68 | { 69 | $this->useExport = $useExport; 70 | 71 | return $this; 72 | } 73 | 74 | public function useResource(bool $useResource = true): static 75 | { 76 | $this->useResource = $useResource; 77 | 78 | return $this; 79 | } 80 | 81 | public function useImport(bool $useImport = true): static 82 | { 83 | $this->useImport = $useImport; 84 | 85 | return $this; 86 | } 87 | 88 | public function useTeams(bool $useTeams = true): static 89 | { 90 | $this->useTeams = $useTeams; 91 | 92 | return $this; 93 | } 94 | 95 | public function useNotifications(bool $useNotifications = true): static 96 | { 97 | $this->useNotifications = $useNotifications; 98 | 99 | return $this; 100 | } 101 | 102 | public function useTypes(bool $useTypes = true): static 103 | { 104 | $this->useTypes = $useTypes; 105 | 106 | return $this; 107 | } 108 | 109 | public function useAvatar(bool $useAvatar = true): static 110 | { 111 | $this->useAvatar = $useAvatar; 112 | 113 | return $this; 114 | } 115 | 116 | public function useLoginBy(bool $useLoginBy = true): static 117 | { 118 | $this->useLoginBy = $useLoginBy; 119 | 120 | return $this; 121 | } 122 | 123 | public function showAddressField(bool $showAddressField = true): static 124 | { 125 | $this->showAddressField = $showAddressField; 126 | 127 | return $this; 128 | } 129 | 130 | public function canLogin(bool $canLogin = true): static 131 | { 132 | $this->canLogin = $canLogin; 133 | 134 | return $this; 135 | } 136 | 137 | public function canBlocked(bool $canBlocked = true): static 138 | { 139 | $this->canBlocked = $canBlocked; 140 | 141 | return $this; 142 | } 143 | 144 | public function useImpersonate(bool $useImpersonate = true): static 145 | { 146 | $this->useImpersonate = $useImpersonate; 147 | 148 | return $this; 149 | } 150 | 151 | public function impersonateRedirect(?string $impersonateRedirect): static 152 | { 153 | $this->impersonateRedirect = $impersonateRedirect; 154 | 155 | return $this; 156 | } 157 | 158 | public function showTypeField(bool $showTypeField = true): static 159 | { 160 | $this->showTypeField = $showTypeField; 161 | 162 | return $this; 163 | } 164 | 165 | public function boot(Panel $panel): void 166 | { 167 | Config::set('filament-accounts.features.notifications', $this->useNotifications); 168 | Config::set('filament-accounts.features.loginBy', $this->useLoginBy); 169 | Config::set('filament-accounts.features.types', $this->useTypes); 170 | Config::set('filament-accounts.features.avatar', $this->useAvatar); 171 | Config::set('filament-accounts.features.impersonate.active', $this->useImpersonate); 172 | Config::set('filament-accounts.features.impersonate.redirect', $this->impersonateRedirect); 173 | 174 | if ($this->showAddressField) { 175 | AccountResource\Form\AccountForm::register(AccountResource\Form\Components\Address::make()); 176 | AccountResource\InfoList\AccountInfoList::register(AccountResource\InfoList\Entries\Address::make()); 177 | } 178 | 179 | if ($this->useAvatar) { 180 | AccountResource\Form\AccountForm::register(AccountResource\Form\Components\Avatar::make()); 181 | AccountResource\InfoList\AccountInfoList::register(AccountResource\InfoList\Entries\Avatar::make()); 182 | AccountResource\Table\AccountTable::register(AccountResource\Table\Columns\Account::make()); 183 | } 184 | 185 | if ($this->useTypes) { 186 | FilamentTypes::register( 187 | TypeFor::make('accounts') 188 | ->label('Accounts') 189 | ->types([ 190 | TypeOf::make('type') 191 | ->label('Type') 192 | ->register([ 193 | Type::make('customer') 194 | ->name([ 195 | 'ar' => 'عميل', 196 | 'en' => 'Customer', 197 | ]) 198 | ->icon('heroicon-c-user-group') 199 | ->color('#d91919'), 200 | Type::make('account') 201 | ->name([ 202 | 'ar' => 'حساب', 203 | 'en' => 'Account', 204 | ]) 205 | ->icon('heroicon-c-user-circle') 206 | ->color('#0a56d9'), 207 | ]), 208 | ]) 209 | ); 210 | AccountResource\Table\AccountFilters::register(AccountResource\Table\Filters\Type::make()); 211 | AccountResource\Form\AccountForm::register(AccountResource\Form\Components\Type::make()); 212 | AccountResource\Table\AccountTable::register(AccountResource\Table\Columns\Type::make()); 213 | AccountResource\InfoList\AccountInfoList::register(AccountResource\InfoList\Entries\Type::make()); 214 | AccountResource\Actions\ManagePageActions::register(AccountResource\Actions\Components\TypesAction::make()); 215 | } 216 | 217 | if ($this->canLogin) { 218 | AccountResource\Table\AccountFilters::register(AccountResource\Table\Filters\IsLogin::make()); 219 | AccountResource\Form\AccountForm::register(AccountResource\Form\Components\IsLogin::make()); 220 | AccountResource\Form\AccountForm::register(AccountResource\Form\Components\Password::make()); 221 | AccountResource\Form\AccountForm::register(AccountResource\Form\Components\PasswordConfirmation::make()); 222 | AccountResource\Table\AccountTable::register(AccountResource\Table\Columns\IsLogin::make()); 223 | AccountResource\Table\AccountActions::register(AccountResource\Table\Actions\ChangePasswordAction::make()); 224 | AccountResource\InfoList\AccountInfoList::register(AccountResource\InfoList\Entries\IsLogin::make()); 225 | } 226 | 227 | if ($this->canBlocked) { 228 | AccountResource\Table\AccountFilters::register(AccountResource\Table\Filters\IsActive::make()); 229 | AccountResource\Form\AccountForm::register(AccountResource\Form\Components\IsActive::make()); 230 | AccountResource\Table\AccountTable::register(AccountResource\Table\Columns\IsActive::make()); 231 | AccountResource\InfoList\AccountInfoList::register(AccountResource\InfoList\Entries\IsActive::make()); 232 | } 233 | 234 | if ($this->useLoginBy) { 235 | AccountResource\Form\AccountForm::register(AccountResource\Form\Components\LoginBy::make()); 236 | AccountResource\InfoList\AccountInfoList::register(AccountResource\InfoList\Entries\LoginBy::make()); 237 | } 238 | 239 | if ($this->useExport) { 240 | AccountResource\Table\AccountHeaderActions::register(AccountResource\Table\HeaderActions\ExportAction::make()); 241 | } 242 | 243 | if ($this->useImport) { 244 | AccountResource\Table\AccountHeaderActions::register(AccountResource\Table\HeaderActions\ImportAction::make()); 245 | } 246 | 247 | if ($this->useImpersonate) { 248 | AccountResource\Table\AccountActions::register(AccountResource\Table\Actions\ImpersonateAction::make()); 249 | } 250 | } 251 | 252 | public static function make(): FilamentAccountsPlugin 253 | { 254 | return new FilamentAccountsPlugin; 255 | } 256 | } 257 | -------------------------------------------------------------------------------- /src/FilamentAccountsServiceProvider.php: -------------------------------------------------------------------------------- 1 | commands([ 13 | \TomatoPHP\FilamentAccounts\Console\FilamentAccountsInstall::class, 14 | ]); 15 | 16 | // Register Config file 17 | $this->mergeConfigFrom(__DIR__ . '/../config/filament-accounts.php', 'filament-accounts'); 18 | 19 | // Publish Config 20 | $this->publishes([ 21 | __DIR__ . '/../config/filament-accounts.php' => config_path('filament-accounts.php'), 22 | ], 'filament-accounts-config'); 23 | 24 | // Register Migrations 25 | $this->loadMigrationsFrom(__DIR__ . '/../database/migrations'); 26 | 27 | // Publish Migrations 28 | $this->publishes([ 29 | __DIR__ . '/../database/migrations' => database_path('migrations'), 30 | ], 'filament-accounts-migrations'); 31 | // Register views 32 | $this->loadViewsFrom(__DIR__ . '/../resources/views', 'filament-accounts'); 33 | 34 | // Publish Views 35 | $this->publishes([ 36 | __DIR__ . '/../resources/views' => resource_path('views/vendor/filament-accounts'), 37 | ], 'filament-accounts-views'); 38 | 39 | // Register Langs 40 | $this->loadTranslationsFrom(__DIR__ . '/../resources/lang', 'filament-accounts'); 41 | 42 | // Publish Lang 43 | $this->publishes([ 44 | __DIR__ . '/../resources/lang' => base_path('lang/vendor/filament-accounts'), 45 | ], 'filament-accounts-lang'); 46 | 47 | $this->publishes([ 48 | __DIR__ . '/../publish/Account.php' => app_path('Models/Account.php'), 49 | ], 'filament-accounts-model'); 50 | 51 | $this->app->bind('filament-accounts', function () { 52 | return new \TomatoPHP\FilamentAccounts\Services\FilamentAccountsServices; 53 | }); 54 | } 55 | 56 | public function boot(): void 57 | { 58 | // 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Import/ImportAccounts.php: -------------------------------------------------------------------------------- 1 | contains(trans('filament-accounts::messages.accounts.columns.id'))) { 15 | continue; 16 | } else { 17 | $account = Account::query()->firstOrCreate([ 18 | 'email' => $row[2] ?? null, 19 | 'phone' => $row[3] ?? null, 20 | 'username' => $row[2] ?? null, 21 | ], [ 22 | 'name' => $row[1], 23 | 'email' => $row[2] ?? null, 24 | 'phone' => $row[3] ?? null, 25 | 'username' => $row[2] ?? null, 26 | 'address' => $row[4] ?? null, 27 | 'type' => $row[5] ?? 'account', 28 | 'is_active' => $row[6] ?? false, 29 | ]); 30 | 31 | if ($account->exists) { 32 | $account->update([ 33 | 'name' => $row[1], 34 | 'email' => $row[2] ?? null, 35 | 'phone' => $row[3] ?? null, 36 | 'username' => $row[2] ?? null, 37 | 'address' => $row[4] ?? null, 38 | 'type' => $row[5] ?? 'account', 39 | 'is_active' => $row[6] ?? false, 40 | ]); 41 | } 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomatophp/filament-accounts/7f5f11765de2781e119f826163e9dcb7a8c1a347/src/Models/.gitkeep -------------------------------------------------------------------------------- /src/Models/Account.php: -------------------------------------------------------------------------------- 1 | 'boolean', 68 | 'is_active' => 'boolean', 69 | ]; 70 | 71 | protected $dates = [ 72 | 'deleted_at', 73 | 'created_at', 74 | 'updated_at', 75 | 'otp_activated_at', 76 | 'last_login', 77 | ]; 78 | 79 | protected $hidden = [ 80 | 'password', 81 | 'remember_token', 82 | 'otp_code', 83 | 'otp_activated_at', 84 | 'host', 85 | 'agent', 86 | ]; 87 | 88 | public function getFilamentAvatarUrl(): ?string 89 | { 90 | return $this->getFirstMediaUrl('avatar') ?? null; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/Services/FilamentAccountsServices.php: -------------------------------------------------------------------------------- 1 | relations[] = $item; 14 | } 15 | } else { 16 | $this->relations[] = $relation; 17 | } 18 | } 19 | 20 | public function getRelations(): array 21 | { 22 | return $this->relations; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/Pest.php: -------------------------------------------------------------------------------- 1 | in(__DIR__); 6 | -------------------------------------------------------------------------------- /tests/database/database.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tomatophp/filament-accounts/7f5f11765de2781e119f826163e9dcb7a8c1a347/tests/database/database.sqlite -------------------------------------------------------------------------------- /tests/database/factories/AccountFactory.php: -------------------------------------------------------------------------------- 1 | faker->unique()->safeEmail(); 16 | 17 | return [ 18 | 'name' => $this->faker->name(), 19 | 'type' => 'account', 20 | 'address' => $this->faker->address(), 21 | 'phone' => $this->faker->unique()->phoneNumber(), 22 | 'email' => $email, 23 | 'username' => $email, 24 | 'loginBy' => 'email', 25 | 'password' => Hash::make($this->faker->password(8)), // password 26 | 'is_active' => 1, 27 | ]; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /tests/database/factories/UserFactory.php: -------------------------------------------------------------------------------- 1 | $this->faker->name(), 17 | 'email' => $this->faker->unique()->safeEmail(), 18 | 'email_verified_at' => now(), 19 | 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password 20 | 'remember_token' => Str::random(10), 21 | ]; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/src/AccountResourceTest.php: -------------------------------------------------------------------------------- 1 | create()); 18 | }); 19 | 20 | it('can render account resource', function () { 21 | get(AccountResource::getUrl())->assertSuccessful(); 22 | }); 23 | 24 | it('can list posts', function () { 25 | Account::query()->delete(); 26 | $accounts = Account::factory()->count(10)->create(); 27 | 28 | livewire(Pages\ListAccounts::class) 29 | ->loadTable() 30 | ->assertCanSeeTableRecords($accounts) 31 | ->assertCountTableRecords(10); 32 | }); 33 | 34 | it('can render account name/email/phone column in table', function () { 35 | Account::factory()->count(10)->create(); 36 | 37 | livewire(Pages\ListAccounts::class) 38 | ->loadTable() 39 | ->assertCanRenderTableColumn('id') 40 | ->assertCanRenderTableColumn('name') 41 | ->assertCanRenderTableColumn('phone') 42 | ->assertCanRenderTableColumn('email'); 43 | }); 44 | 45 | it('can render account list page', function () { 46 | livewire(Pages\ListAccounts::class)->assertSuccessful(); 47 | }); 48 | 49 | it('can render view account action', function () { 50 | livewire(Pages\ManageAccounts::class, [ 51 | 'record' => Account::factory()->create(), 52 | ]) 53 | ->mountAction('view') 54 | ->assertSuccessful(); 55 | }); 56 | 57 | it('can render view account page', function () { 58 | get(AccountResource::getUrl('view', [ 59 | 'record' => Account::factory()->create(), 60 | ]))->assertSuccessful(); 61 | }); 62 | 63 | it('can render account create action', function () { 64 | livewire(Pages\ManageAccounts::class) 65 | ->mountAction('create') 66 | ->assertSuccessful(); 67 | }); 68 | 69 | it('can render account create page', function () { 70 | get(AccountResource::getUrl('create'))->assertSuccessful(); 71 | }); 72 | 73 | it('can create new account', function () { 74 | $newData = Account::factory()->make(); 75 | 76 | $password = str()->random(10); 77 | 78 | livewire(Pages\CreateAccount::class) 79 | ->fillForm([ 80 | 'name' => $newData->name, 81 | 'email' => $newData->email, 82 | 'phone' => $newData->phone, 83 | ]) 84 | ->call('create') 85 | ->assertHasNoFormErrors(); 86 | 87 | assertDatabaseHas(Account::class, [ 88 | 'name' => $newData->name, 89 | 'email' => $newData->email, 90 | 'phone' => $newData->phone, 91 | ]); 92 | }); 93 | 94 | it('can validate account input', function () { 95 | livewire(Pages\CreateAccount::class) 96 | ->fillForm([ 97 | 'name' => null, 98 | ]) 99 | ->call('create') 100 | ->assertHasFormErrors([ 101 | 'name' => 'required', 102 | ]); 103 | }); 104 | 105 | it('can render account edit action', function () { 106 | livewire(Pages\ManageAccounts::class, [ 107 | 'record' => Account::factory()->create(), 108 | ]) 109 | ->mountAction('edit') 110 | ->assertSuccessful(); 111 | }); 112 | 113 | it('can render account edit page', function () { 114 | get(AccountResource::getUrl('edit', [ 115 | 'record' => Account::factory()->create(), 116 | ]))->assertSuccessful(); 117 | }); 118 | 119 | it('can retrieve account data', function () { 120 | $account = Account::factory()->create(); 121 | 122 | livewire(Pages\EditAccount::class, [ 123 | 'record' => $account->getRouteKey(), 124 | ]) 125 | ->assertFormSet([ 126 | 'name' => $account->name, 127 | 'email' => $account->email, 128 | ]); 129 | }); 130 | 131 | it('can validate edit account input', function () { 132 | $account = Account::factory()->create(); 133 | 134 | livewire(Pages\EditAccount::class, [ 135 | 'record' => $account->getRouteKey(), 136 | ]) 137 | ->fillForm([ 138 | 'name' => null, 139 | ]) 140 | ->call('save') 141 | ->assertHasFormErrors([ 142 | 'name' => 'required', 143 | ]); 144 | }); 145 | 146 | it('can save account data', function () { 147 | $account = Account::factory()->create(); 148 | $newData = Account::factory()->make(); 149 | 150 | livewire(Pages\EditAccount::class, [ 151 | 'record' => $account->getRouteKey(), 152 | ]) 153 | ->fillForm([ 154 | 'name' => $newData->name, 155 | 'email' => $newData->email, 156 | ]) 157 | ->call('save') 158 | ->assertHasNoFormErrors(); 159 | 160 | expect($account->refresh()) 161 | ->name->toBe($newData->name) 162 | ->email->toBe($newData->email); 163 | }); 164 | 165 | it('can delete account', function () { 166 | $account = Account::factory()->create(); 167 | 168 | livewire(Pages\EditAccount::class, [ 169 | 'record' => $account->getRouteKey(), 170 | ]) 171 | ->callAction('deleteSelectedAccount'); 172 | 173 | assertNotEmpty(Account::query()->withTrashed()->find($account->getRouteKey())->deleted_at); 174 | }); 175 | -------------------------------------------------------------------------------- /tests/src/AdminPanelProvider.php: -------------------------------------------------------------------------------- 1 | default() 26 | ->id('admin') 27 | ->path('admin') 28 | ->login() 29 | ->pages([ 30 | Pages\Dashboard::class, 31 | ]) 32 | ->plugin( 33 | FilamentAccountsPlugin::make() 34 | ) 35 | ->middleware([ 36 | EncryptCookies::class, 37 | AddQueuedCookiesToResponse::class, 38 | StartSession::class, 39 | AuthenticateSession::class, 40 | ShareErrorsFromSession::class, 41 | VerifyCsrfToken::class, 42 | SubstituteBindings::class, 43 | DisableBladeIconComponents::class, 44 | DispatchServingFilamentEvent::class, 45 | ]) 46 | ->authMiddleware([ 47 | Authenticate::class, 48 | ]); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /tests/src/DebugTest.php: -------------------------------------------------------------------------------- 1 | each->not->toBeUsed(); 5 | }); 6 | -------------------------------------------------------------------------------- /tests/src/Models/Account.php: -------------------------------------------------------------------------------- 1 | 'boolean', 69 | 'is_active' => 'boolean', 70 | ]; 71 | 72 | protected $dates = [ 73 | 'deleted_at', 74 | 'created_at', 75 | 'updated_at', 76 | 'otp_activated_at', 77 | 'last_login', 78 | ]; 79 | 80 | protected $hidden = [ 81 | 'password', 82 | 'remember_token', 83 | 'otp_code', 84 | 'otp_activated_at', 85 | 'host', 86 | 'agent', 87 | ]; 88 | 89 | public function getFilamentAvatarUrl(): ?string 90 | { 91 | return $this->getFirstMediaUrl('avatar') ?? null; 92 | } 93 | 94 | protected static function newFactory(): AccountFactory 95 | { 96 | return AccountFactory::new(); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /tests/src/Models/User.php: -------------------------------------------------------------------------------- 1 | plugins([ 10 | FilamentAccountsPlugin::make(), 11 | ]); 12 | 13 | expect($panel->getPlugin('filament-accounts')) 14 | ->not() 15 | ->toThrow(Exception::class); 16 | }); 17 | 18 | // it('can modify avatar', function ($condition) { 19 | // $plugin = FilamentAccountsPlugin::make() 20 | // ->useAvatar($condition); 21 | // 22 | // expect($plugin::hasAvatar())->toBe($condition); 23 | // })->with([ 24 | // false, 25 | // fn () => true, 26 | // ]); 27 | -------------------------------------------------------------------------------- /tests/src/TestCase.php: -------------------------------------------------------------------------------- 1 | loadMigrationsFrom(__DIR__ . '/../../database/migrations'); 54 | } 55 | 56 | public function getEnvironmentSetUp($app): void 57 | { 58 | $app['config']->set('filament-accounts.simple', false); 59 | $app['config']->set('database.default', 'sqlite'); 60 | $app['config']->set('database.connections.sqlite.database', __DIR__ . '/../database/database.sqlite'); 61 | 62 | $app['config']->set('view.paths', [ 63 | ...$app['config']->get('view.paths'), 64 | __DIR__ . '/../resources/views', 65 | ]); 66 | } 67 | } 68 | --------------------------------------------------------------------------------