├── database ├── .gitignore ├── factories │ ├── OrganizationFactory.php │ ├── ContactFactory.php │ └── UserFactory.php ├── migrations │ ├── 2020_01_01_000003_create_accounts_table.php │ ├── 2020_01_01_000001_create_password_resets_table.php │ ├── 2020_01_01_000002_create_failed_jobs_table.php │ ├── 2019_12_14_000001_create_personal_access_tokens_table.php │ ├── 2020_01_01_000004_create_users_table.php │ ├── 2020_01_01_000005_create_organizations_table.php │ └── 2020_01_01_000006_create_contacts_table.php └── seeders │ └── DatabaseSeeder.php ├── .github └── FUNDING.yml ├── bootstrap ├── cache │ └── .gitignore └── app.php ├── storage ├── logs │ └── .gitignore ├── app │ ├── public │ │ └── .gitignore │ └── .gitignore ├── debugbar │ └── .gitignore └── framework │ ├── testing │ └── .gitignore │ ├── views │ └── .gitignore │ ├── cache │ ├── data │ │ └── .gitignore │ └── .gitignore │ ├── sessions │ └── .gitignore │ └── .gitignore ├── public ├── robots.txt ├── .htaccess ├── favicon.svg ├── web.config └── index.php ├── Procfile ├── screenshot.png ├── resources ├── css │ ├── reset.css │ ├── app.css │ ├── buttons.css │ └── form.css ├── js │ ├── Shared │ │ ├── LoadingButton.vue │ │ ├── TrashedMessage.vue │ │ ├── Pagination.vue │ │ ├── TextareaInput.vue │ │ ├── TextInput.vue │ │ ├── SelectInput.vue │ │ ├── Dropdown.vue │ │ ├── SearchFilter.vue │ │ ├── FileInput.vue │ │ ├── Icon.vue │ │ ├── MainMenu.vue │ │ ├── Logo.vue │ │ ├── FlashMessages.vue │ │ └── Layout.vue │ ├── Pages │ │ ├── Reports │ │ │ └── Index.vue │ │ ├── Dashboard │ │ │ └── Index.vue │ │ ├── Auth │ │ │ └── Login.vue │ │ ├── Users │ │ │ ├── Create.vue │ │ │ ├── Edit.vue │ │ │ └── Index.vue │ │ ├── Organizations │ │ │ ├── Create.vue │ │ │ ├── Index.vue │ │ │ └── Edit.vue │ │ └── Contacts │ │ │ ├── Create.vue │ │ │ ├── Index.vue │ │ │ └── Edit.vue │ ├── ssr.js │ └── app.js ├── lang │ └── en │ │ ├── pagination.php │ │ ├── auth.php │ │ └── passwords.php └── views │ └── app.blade.php ├── .gitattributes ├── .prettierrc ├── tests ├── TestCase.php ├── Unit │ └── ExampleTest.php ├── CreatesApplication.php └── Feature │ ├── OrganizationsTest.php │ └── ContactsTest.php ├── .styleci.yml ├── app ├── Http │ ├── Controllers │ │ ├── ReportsController.php │ │ ├── DashboardController.php │ │ ├── Controller.php │ │ ├── ImagesController.php │ │ ├── Auth │ │ │ └── AuthenticatedSessionController.php │ │ ├── OrganizationsController.php │ │ ├── UsersController.php │ │ └── ContactsController.php │ ├── Middleware │ │ ├── EncryptCookies.php │ │ ├── VerifyCsrfToken.php │ │ ├── PreventRequestsDuringMaintenance.php │ │ ├── TrustHosts.php │ │ ├── TrimStrings.php │ │ ├── Authenticate.php │ │ ├── TrustProxies.php │ │ ├── RedirectIfAuthenticated.php │ │ └── HandleInertiaRequests.php │ ├── Requests │ │ └── Auth │ │ │ └── LoginRequest.php │ └── Kernel.php ├── Models │ ├── Account.php │ ├── Organization.php │ ├── Contact.php │ └── User.php ├── Providers │ ├── BroadcastServiceProvider.php │ ├── AppServiceProvider.php │ ├── AuthServiceProvider.php │ ├── EventServiceProvider.php │ └── RouteServiceProvider.php ├── Console │ └── Kernel.php └── Exceptions │ └── Handler.php ├── .editorconfig ├── .gitignore ├── webpack.ssr.mix.js ├── webpack.config.js ├── server.php ├── routes ├── channels.php ├── api.php ├── console.php └── web.php ├── config ├── cors.php ├── services.php ├── view.php ├── inertia.php ├── hashing.php ├── broadcasting.php ├── sanctum.php ├── filesystems.php ├── queue.php ├── cache.php ├── logging.php ├── mail.php ├── auth.php └── database.php ├── .eslintrc.js ├── webpack.mix.js ├── .env.example ├── LICENSE ├── phpunit.xml ├── tailwind.config.js ├── readme.md ├── package.json ├── artisan ├── composer.json └── .php-cs-fixer.dist.php /database/.gitignore: -------------------------------------------------------------------------------- 1 | *.sqlite* 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [reinink] 2 | -------------------------------------------------------------------------------- /bootstrap/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/logs/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /storage/app/public/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/debugbar/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: vendor/bin/heroku-php-apache2 public/ 2 | -------------------------------------------------------------------------------- /storage/app/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !public/ 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /storage/framework/testing/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/views/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/cache/data/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/sessions/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/framework/cache/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !data/ 3 | !.gitignore 4 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/inertiajs/pingcrm-vue2/HEAD/screenshot.png -------------------------------------------------------------------------------- /resources/css/reset.css: -------------------------------------------------------------------------------- 1 | input, select, textarea, button, div, a { 2 | &:focus, &:active { 3 | outline: none; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.css linguist-vendored 3 | *.scss linguist-vendored 4 | *.js linguist-vendored 5 | CHANGELOG.md export-ignore 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 10000, 3 | "semi": false, 4 | "singleQuote": true, 5 | "tabWidth": 2, 6 | "trailingComma": "all", 7 | "htmlWhitespaceSensitivity": "css" 8 | } 9 | -------------------------------------------------------------------------------- /storage/framework/.gitignore: -------------------------------------------------------------------------------- 1 | compiled.php 2 | config.php 3 | down 4 | events.scanned.php 5 | maintenance.php 6 | routes.php 7 | routes.scanned.php 8 | schedule-* 9 | services.json 10 | -------------------------------------------------------------------------------- /tests/TestCase.php: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 15 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | end_of_line = lf 6 | insert_final_newline = true 7 | indent_style = space 8 | indent_size = 4 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | 14 | [*.{yml,yaml,vue}] 15 | indent_size = 2 16 | 17 | [docker-compose.yml] 18 | indent_size = 4 19 | -------------------------------------------------------------------------------- /tests/Unit/ExampleTest.php: -------------------------------------------------------------------------------- 1 | assertTrue(true); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /public/css 3 | /public/hot 4 | /public/js 5 | /public/mix-manifest.json 6 | /public/storage 7 | /storage/*.key 8 | /vendor 9 | .DS_Store 10 | .env 11 | .env.backup 12 | .phpunit.result.cache 13 | .php-cs-fixer.php 14 | .php-cs-fixer.cache 15 | docker-compose.override.yml 16 | Homestead.json 17 | Homestead.yaml 18 | npm-debug.log 19 | yarn-error.log 20 | /.idea 21 | /.vscode 22 | -------------------------------------------------------------------------------- /resources/js/Pages/Reports/Index.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 19 | -------------------------------------------------------------------------------- /app/Http/Middleware/EncryptCookies.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | protected $except = [ 15 | // 16 | ]; 17 | } 18 | -------------------------------------------------------------------------------- /app/Http/Middleware/VerifyCsrfToken.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | protected $except = [ 15 | // 16 | ]; 17 | } 18 | -------------------------------------------------------------------------------- /app/Http/Controllers/Controller.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | protected $except = [ 15 | // 16 | ]; 17 | } 18 | -------------------------------------------------------------------------------- /app/Http/Middleware/TrustHosts.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | public function hosts() 15 | { 16 | return [ 17 | $this->allSubdomainsOfApplicationUrl(), 18 | ]; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /app/Http/Middleware/TrimStrings.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | protected $except = [ 15 | 'current_password', 16 | 'password', 17 | 'password_confirmation', 18 | ]; 19 | } 20 | -------------------------------------------------------------------------------- /app/Models/Account.php: -------------------------------------------------------------------------------- 1 | hasMany(User::class); 12 | } 13 | 14 | public function organizations() 15 | { 16 | return $this->hasMany(Organization::class); 17 | } 18 | 19 | public function contacts() 20 | { 21 | return $this->hasMany(Contact::class); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tests/CreatesApplication.php: -------------------------------------------------------------------------------- 1 | make(Kernel::class)->bootstrap(); 19 | 20 | return $app; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/Providers/BroadcastServiceProvider.php: -------------------------------------------------------------------------------- 1 | expectsJson()) { 18 | return route('login'); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /resources/js/ssr.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import { createRenderer } from 'vue-server-renderer' 3 | import { createInertiaApp } from '@inertiajs/inertia-vue' 4 | import createServer from '@inertiajs/server' 5 | 6 | createServer((page) => createInertiaApp({ 7 | page, 8 | render: createRenderer().renderToString, 9 | resolve: name => require(`./Pages/${name}`), 10 | title: title => title ? `${title} - Ping CRM` : 'Ping CRM', 11 | setup({ app, props, plugin }) { 12 | Vue.use(plugin) 13 | return new Vue({ 14 | render: h => h(app, props), 15 | }) 16 | }, 17 | })) 18 | -------------------------------------------------------------------------------- /resources/js/app.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import PortalVue from 'portal-vue' 3 | import { InertiaProgress } from '@inertiajs/progress' 4 | import { createInertiaApp } from '@inertiajs/inertia-vue' 5 | 6 | Vue.config.productionTip = false 7 | Vue.use(PortalVue) 8 | 9 | InertiaProgress.init() 10 | 11 | createInertiaApp({ 12 | resolve: name => require(`./Pages/${name}`), 13 | title: title => title ? `${title} - Ping CRM` : 'Ping CRM', 14 | setup({ el, app, props, plugin }) { 15 | Vue.use(plugin) 16 | new Vue({ render: h => h(app, props) }) 17 | .$mount(el) 18 | }, 19 | }) 20 | -------------------------------------------------------------------------------- /app/Providers/AppServiceProvider.php: -------------------------------------------------------------------------------- 1 | 7 | */ 8 | $uri = urldecode( 9 | parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH) 10 | ); 11 | 12 | // This file allows us to emulate Apache's "mod_rewrite" functionality from the 13 | // built-in PHP web server. This provides a convenient way to test a Laravel 14 | // application without having installed a "real" web server software here. 15 | if ($uri !== '/' && file_exists(__DIR__.'/public'.$uri)) { 16 | return false; 17 | } 18 | 19 | require_once __DIR__.'/public/index.php'; 20 | -------------------------------------------------------------------------------- /resources/js/Pages/Dashboard/Index.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 20 | -------------------------------------------------------------------------------- /resources/lang/en/pagination.php: -------------------------------------------------------------------------------- 1 | '« Previous', 17 | 'next' => 'Next »', 18 | 19 | ]; 20 | -------------------------------------------------------------------------------- /routes/channels.php: -------------------------------------------------------------------------------- 1 | id === (int) $id; 18 | }); 19 | -------------------------------------------------------------------------------- /routes/api.php: -------------------------------------------------------------------------------- 1 | get('/user', function (Request $request) { 18 | return $request->user(); 19 | }); 20 | -------------------------------------------------------------------------------- /routes/console.php: -------------------------------------------------------------------------------- 1 | comment(Inspiring::quote()); 19 | })->purpose('Display an inspiring quote'); 20 | -------------------------------------------------------------------------------- /public/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | 3 | Options -MultiViews -Indexes 4 | 5 | 6 | RewriteEngine On 7 | 8 | # Handle Authorization Header 9 | RewriteCond %{HTTP:Authorization} . 10 | RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] 11 | 12 | # Redirect Trailing Slashes If Not A Folder... 13 | RewriteCond %{REQUEST_FILENAME} !-d 14 | RewriteCond %{REQUEST_URI} (.+)/$ 15 | RewriteRule ^ %1 [L,R=301] 16 | 17 | # Send Requests To Front Controller... 18 | RewriteCond %{REQUEST_FILENAME} !-d 19 | RewriteCond %{REQUEST_FILENAME} !-f 20 | RewriteRule ^ index.php [L] 21 | 22 | -------------------------------------------------------------------------------- /resources/js/Shared/TrashedMessage.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 23 | -------------------------------------------------------------------------------- /app/Providers/AuthServiceProvider.php: -------------------------------------------------------------------------------- 1 | 13 | */ 14 | protected $policies = [ 15 | // 'App\Models\Model' => 'App\Policies\ModelPolicy', 16 | ]; 17 | 18 | /** 19 | * Register any authentication / authorization services. 20 | * 21 | * @return void 22 | */ 23 | public function boot() 24 | { 25 | $this->registerPolicies(); 26 | 27 | // 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /resources/lang/en/auth.php: -------------------------------------------------------------------------------- 1 | 'These credentials do not match our records.', 17 | 'password' => 'The provided password is incorrect.', 18 | 'throttle' => 'Too many login attempts. Please try again in :seconds seconds.', 19 | 20 | ]; 21 | -------------------------------------------------------------------------------- /public/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/Http/Controllers/ImagesController.php: -------------------------------------------------------------------------------- 1 | new LaravelResponseFactory($request), 16 | 'source' => $filesystem->getDriver(), 17 | 'cache' => $filesystem->getDriver(), 18 | 'cache_path_prefix' => '.glide-cache', 19 | ]); 20 | 21 | return $server->getImageResponse($path, $request->all()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/Http/Middleware/TrustProxies.php: -------------------------------------------------------------------------------- 1 | |string|null 14 | */ 15 | protected $proxies; 16 | 17 | /** 18 | * The headers that should be used to detect proxies. 19 | * 20 | * @var int 21 | */ 22 | protected $headers = 23 | Request::HEADER_X_FORWARDED_FOR | 24 | Request::HEADER_X_FORWARDED_HOST | 25 | Request::HEADER_X_FORWARDED_PORT | 26 | Request::HEADER_X_FORWARDED_PROTO | 27 | Request::HEADER_X_FORWARDED_AWS_ELB; 28 | } 29 | -------------------------------------------------------------------------------- /resources/css/buttons.css: -------------------------------------------------------------------------------- 1 | .btn-indigo { 2 | @apply px-6 py-3 rounded bg-indigo-600 text-white text-sm leading-4 font-bold whitespace-nowrap hover:bg-orange-400 focus:bg-orange-400; 3 | } 4 | 5 | .btn-spinner, 6 | .btn-spinner:after { 7 | border-radius: 50%; 8 | width: 1.5em; 9 | height: 1.5em; 10 | } 11 | 12 | .btn-spinner { 13 | font-size: 10px; 14 | position: relative; 15 | text-indent: -9999em; 16 | border-top: 0.2em solid white; 17 | border-right: 0.2em solid white; 18 | border-bottom: 0.2em solid white; 19 | border-left: 0.2em solid transparent; 20 | transform: translateZ(0); 21 | animation: spinning 1s infinite linear; 22 | } 23 | 24 | @keyframes spinning { 25 | 0% { 26 | transform: rotate(0deg); 27 | } 28 | 100% { 29 | transform: rotate(360deg); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /database/factories/OrganizationFactory.php: -------------------------------------------------------------------------------- 1 | $this->faker->company, 18 | 'email' => $this->faker->companyEmail, 19 | 'phone' => $this->faker->tollFreePhoneNumber, 20 | 'address' => $this->faker->streetAddress, 21 | 'city' => $this->faker->city, 22 | 'region' => $this->faker->state, 23 | 'country' => 'US', 24 | 'postal_code' => $this->faker->postcode, 25 | ]; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /database/migrations/2020_01_01_000003_create_accounts_table.php: -------------------------------------------------------------------------------- 1 | increments('id'); 18 | $table->string('name', 50); 19 | $table->timestamps(); 20 | }); 21 | } 22 | 23 | /** 24 | * Reverse the migrations. 25 | * 26 | * @return void 27 | */ 28 | public function down() 29 | { 30 | Schema::dropIfExists('accounts'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /app/Console/Kernel.php: -------------------------------------------------------------------------------- 1 | command('inspire')->hourly(); 19 | } 20 | 21 | /** 22 | * Register the commands for the application. 23 | * 24 | * @return void 25 | */ 26 | protected function commands() 27 | { 28 | $this->load(__DIR__.'/Commands'); 29 | 30 | require base_path('routes/console.php'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /resources/js/Shared/Pagination.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 24 | -------------------------------------------------------------------------------- /resources/lang/en/passwords.php: -------------------------------------------------------------------------------- 1 | 'Your password has been reset!', 17 | 'sent' => 'We have emailed your password reset link!', 18 | 'throttled' => 'Please wait before retrying.', 19 | 'token' => 'This password reset token is invalid.', 20 | 'user' => "We can't find a user with that email address.", 21 | 22 | ]; 23 | -------------------------------------------------------------------------------- /database/factories/ContactFactory.php: -------------------------------------------------------------------------------- 1 | $this->faker->firstName, 18 | 'last_name' => $this->faker->lastName, 19 | 'email' => $this->faker->unique()->safeEmail, 20 | 'phone' => $this->faker->tollFreePhoneNumber, 21 | 'address' => $this->faker->streetAddress, 22 | 'city' => $this->faker->city, 23 | 'region' => $this->faker->state, 24 | 'country' => 'US', 25 | 'postal_code' => $this->faker->postcode, 26 | ]; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /database/migrations/2020_01_01_000001_create_password_resets_table.php: -------------------------------------------------------------------------------- 1 | string('email')->index(); 18 | $table->string('token'); 19 | $table->timestamp('created_at')->nullable(); 20 | }); 21 | } 22 | 23 | /** 24 | * Reverse the migrations. 25 | * 26 | * @return void 27 | */ 28 | public function down() 29 | { 30 | Schema::dropIfExists('password_resets'); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /resources/views/app.blade.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | {{-- Inertia --}} 10 | 11 | 12 | {{-- Ping CRM --}} 13 | 14 | 15 | 16 | @inertiaHead 17 | 18 | 19 | @inertia 20 | 21 | 22 | -------------------------------------------------------------------------------- /app/Providers/EventServiceProvider.php: -------------------------------------------------------------------------------- 1 | > 16 | */ 17 | protected $listen = [ 18 | Registered::class => [ 19 | SendEmailVerificationNotification::class, 20 | ], 21 | ]; 22 | 23 | /** 24 | * Register any events for your application. 25 | * 26 | * @return void 27 | */ 28 | public function boot() 29 | { 30 | // 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /resources/js/Shared/TextareaInput.vue: -------------------------------------------------------------------------------- 1 |