mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-11-04 04:07:32 -05:00 
			
		
		
		
	Show custom messages (#3616)
* Show custom messages * Fix getSetting key * Add custom messages support with variable parsing
This commit is contained in:
		
							parent
							
								
									e3446e906f
								
							
						
					
					
						commit
						f118f3bfda
					
				
							
								
								
									
										31
									
								
								app/Providers/ClientPortalServiceProvider.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								app/Providers/ClientPortalServiceProvider.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,31 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace App\Providers;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Utils\ClientPortal\CustomMessage\CustomMessage;
 | 
				
			||||||
 | 
					use Illuminate\Support\ServiceProvider;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ClientPortalServiceProvider extends ServiceProvider
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Register services.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function register()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        app()->bind('customMessage', function () {
 | 
				
			||||||
 | 
					            return new CustomMessage();
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Bootstrap services.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return void
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public function boot()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        //
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										130
									
								
								app/Utils/ClientPortal/CustomMessage/CustomMessage.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										130
									
								
								app/Utils/ClientPortal/CustomMessage/CustomMessage.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,130 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace App\Utils\ClientPortal\CustomMessage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use App\Models\Client;
 | 
				
			||||||
 | 
					use App\Models\ClientContact;
 | 
				
			||||||
 | 
					use App\Models\Company;
 | 
				
			||||||
 | 
					use App\Models\GroupSetting;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class CustomMessage
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    protected $message;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $values;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $company;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $contact;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $group;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $entity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    protected $invitation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function client(Client $client): self
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->client = $client;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function company(Company $company): self
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->company = $company;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function contact(ClientContact $contact): self
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->contact = $contact;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function group(GroupSetting $group): self
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->group = $group;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function entity($entity): self
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->entity = $entity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function invitation($invitation): self
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->invitation = $invitation;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return $this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    public function message(string $message): string
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        $this->message = $message;
 | 
				
			||||||
 | 
					        $this->values = $this->compose();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        return strtr($message, $this->values);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private function compose(): array
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return [
 | 
				
			||||||
 | 
					            '$company.id' => optional($this->company)->id,
 | 
				
			||||||
 | 
					            '$company.name' => optional($this->company)->getSetting('name'),
 | 
				
			||||||
 | 
					            '$company.website' => optional($this->company)->getSetting('website'),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            '$client.id' => optional(optional($this->client)->present())->id,
 | 
				
			||||||
 | 
					            '$client.name' => optional(optional($this->client)->present())->name,
 | 
				
			||||||
 | 
					            '$client.website' => optional(optional($this->client)->present())->website,
 | 
				
			||||||
 | 
					            '$client.public_notes' => optional(optional($this->client)->present())->public_notes,
 | 
				
			||||||
 | 
					            '$client.phone' => optional(optional($this->client)->present())->phone,
 | 
				
			||||||
 | 
					            '$client.balance' => optional(optional($this->client)->present())->balance,
 | 
				
			||||||
 | 
					            '$client.address1' => optional(optional($this->client)->present())->address1,
 | 
				
			||||||
 | 
					            '$client.address2' => optional(optional($this->client)->present())->address2,
 | 
				
			||||||
 | 
					            '$client.city' => optional(optional($this->client)->present())->city,
 | 
				
			||||||
 | 
					            '$client.state' => optional(optional($this->client)->present())->state,
 | 
				
			||||||
 | 
					            '$client.postal_code' => optional(optional($this->client)->present())->postal_code,
 | 
				
			||||||
 | 
					            '$client.country' => optional(optional(optional($this->client)->present())->country)->full_name,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            '$contact.first_name' => optional($this->contact)->first_name,
 | 
				
			||||||
 | 
					            '$contact.last_name' => optional($this->contact)->last_name,
 | 
				
			||||||
 | 
					            '$contact.phone' => optional($this->contact)->phone,
 | 
				
			||||||
 | 
					            '$contact.email' => optional($this->contact)->email,
 | 
				
			||||||
 | 
					            '$contact.avatar' => optional($this->contact)->avatar,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            '$group.id' => optional($this->group)->id,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            '$entity.id' => optional($this->entity)->hashed_id,
 | 
				
			||||||
 | 
					            '$entity.number' => optional($this->entity)->number,
 | 
				
			||||||
 | 
					            '$entity.discount' => optional($this->entity)->discount,
 | 
				
			||||||
 | 
					            '$entity.date' => optional($this->entity)->date, // Todo: Handle formatDate
 | 
				
			||||||
 | 
					            '$entity.due_date' => optional($this->entity)->due_date, // Todo: Handle formatDate
 | 
				
			||||||
 | 
					            '$entity.last_sent_date' => optional($this->entity)->last_sent_date,
 | 
				
			||||||
 | 
					            '$entity.public_notes' => optional($this->entity)->public_notes,
 | 
				
			||||||
 | 
					            '$entity.terms' => optional($this->entity)->terms,
 | 
				
			||||||
 | 
					            '$entity.amount' => optional($this->entity)->amount, // Todo: Handle moneyformat
 | 
				
			||||||
 | 
					            '$entity.balance' => optional($this->entity)->balance, // Todo: Handle moneyformat
 | 
				
			||||||
 | 
					            '$entity.created_at' => optional($this->entity)->created_at, // Todo: Handle formatDate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            '$entity.status' => optional(optional($this->entity))->badgeForStatus(optional($this->entity)->status_id), // It would be nice if we have method that will only return status as text, not with markup.
 | 
				
			||||||
 | 
					            '$entity.project' => optional(optional($this->entity)->project)->name,
 | 
				
			||||||
 | 
					            '$entity.project.date' => optional(optional($this->entity)->project)->date,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            '$invitation.id' => optional($this->invitation)->id,
 | 
				
			||||||
 | 
					            '$invitation.user.first_name' => optional(optional($this->invitation)->user)->first_name,
 | 
				
			||||||
 | 
					            '$invitation.user.last_name' => optional(optional($this->invitation)->user)->last_name,
 | 
				
			||||||
 | 
					            '$invitation.sent_date' => optional($this->invitation)->sent_date, // Todo: Handle formatDate
 | 
				
			||||||
 | 
					            '$invitation.viewed_date' => optional($this->invitation)->viewed_date, // Todo: Handle formatDate,
 | 
				
			||||||
 | 
					            '$invitation.opened_date' => optional($this->invitation)->opened_date, // Todo: Handle formatDate,
 | 
				
			||||||
 | 
					        ];
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										13
									
								
								app/Utils/ClientPortal/CustomMessage/CustomMessageFacade.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								app/Utils/ClientPortal/CustomMessage/CustomMessageFacade.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					<?php
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace App\Utils\ClientPortal\CustomMessage;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					use Illuminate\Support\Facades\Facade;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ClientPortalFacade extends Facade
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    protected static function getFacadeAccessor()
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return 'customMessage';
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -180,7 +180,7 @@ return [
 | 
				
			|||||||
        App\Providers\ComposerServiceProvider::class,
 | 
					        App\Providers\ComposerServiceProvider::class,
 | 
				
			||||||
        Codedge\Updater\UpdaterServiceProvider::class,
 | 
					        Codedge\Updater\UpdaterServiceProvider::class,
 | 
				
			||||||
        App\Providers\MultiDBProvider::class,
 | 
					        App\Providers\MultiDBProvider::class,
 | 
				
			||||||
 | 
					        App\Providers\ClientPortalServiceProvider::class,
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
@ -235,7 +235,7 @@ return [
 | 
				
			|||||||
         */
 | 
					         */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        'Countries' => 'Webpatser\Countries\CountriesFacade',
 | 
					        'Countries' => 'Webpatser\Countries\CountriesFacade',
 | 
				
			||||||
 | 
					        'CustomMessage' => App\Utils\ClientPortal\CustomMessage\ClientPortalFacade::class,
 | 
				
			||||||
    ],
 | 
					    ],
 | 
				
			||||||
 | 
					
 | 
				
			||||||
];
 | 
					];
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										2
									
								
								public/css/app.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								public/css/app.css
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -1,6 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    "/js/app.js": "/js/app.js?id=8b49701583f407403ddf",
 | 
					    "/js/app.js": "/js/app.js?id=8b49701583f407403ddf",
 | 
				
			||||||
    "/css/app.css": "/css/app.css?id=94397d09115c3157cc49",
 | 
					    "/css/app.css": "/css/app.css?id=54b56cad767e049a84d7",
 | 
				
			||||||
    "/js/clients/invoices/action-selectors.js": "/js/clients/invoices/action-selectors.js?id=caec43815d9a13168a38",
 | 
					    "/js/clients/invoices/action-selectors.js": "/js/clients/invoices/action-selectors.js?id=caec43815d9a13168a38",
 | 
				
			||||||
    "/js/clients/invoices/payment.js": "/js/clients/invoices/payment.js?id=af49e24958be5fc00c92",
 | 
					    "/js/clients/invoices/payment.js": "/js/clients/invoices/payment.js?id=af49e24958be5fc00c92",
 | 
				
			||||||
    "/js/clients/payment_methods/authorize-stripe-card.js": "/js/clients/payment_methods/authorize-stripe-card.js?id=f4c45f0da9868d840799",
 | 
					    "/js/clients/payment_methods/authorize-stripe-card.js": "/js/clients/payment_methods/authorize-stripe-card.js?id=f4c45f0da9868d840799",
 | 
				
			||||||
 | 
				
			|||||||
@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					<div class="alert border-blue-500 bg-blue-50 mt-2 mb-4">
 | 
				
			||||||
 | 
					    {{ $slot }}
 | 
				
			||||||
 | 
					</div>
 | 
				
			||||||
@ -4,6 +4,14 @@
 | 
				
			|||||||
@section('header')
 | 
					@section('header')
 | 
				
			||||||
    {{ Breadcrumbs::render('dashboard') }}
 | 
					    {{ Breadcrumbs::render('dashboard') }}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @if(!empty($client->getSetting('custom_message_dashboard')))
 | 
				
			||||||
 | 
					        @component('portal.ninja2020.components.message')
 | 
				
			||||||
 | 
					            {!! CustomMessage::client($client)
 | 
				
			||||||
 | 
					                ->company($client->company)
 | 
				
			||||||
 | 
					                ->message($client->getSetting('custom_message_dashboard')) !!}
 | 
				
			||||||
 | 
					        @endcomponent
 | 
				
			||||||
 | 
					    @endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    <div class="bg-white shadow rounded mb-4" translate>
 | 
					    <div class="bg-white shadow rounded mb-4" translate>
 | 
				
			||||||
        <div class="px-4 py-5 sm:p-6">
 | 
					        <div class="px-4 py-5 sm:p-6">
 | 
				
			||||||
            <div class="sm:flex sm:items-start sm:justify-between">
 | 
					            <div class="sm:flex sm:items-start sm:justify-between">
 | 
				
			||||||
 | 
				
			|||||||
@ -12,6 +12,24 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@section('body')
 | 
					@section('body')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @if($invoice->isPayable() && !empty($client->getSetting('custom_message_unpaid_invoice')))
 | 
				
			||||||
 | 
					        @component('portal.ninja2020.components.message')
 | 
				
			||||||
 | 
					            {!! CustomMessage::client($client)
 | 
				
			||||||
 | 
					                ->company($client->company)
 | 
				
			||||||
 | 
					                ->entity($invoice)
 | 
				
			||||||
 | 
					                ->message($client->getSetting('custom_message_unpaid_invoice')) !!}
 | 
				
			||||||
 | 
					        @endcomponent
 | 
				
			||||||
 | 
					    @endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @if(!$invoice->isPayable() && !empty($client->getSetting('custom_message_paid_invoice')))
 | 
				
			||||||
 | 
					        @component('portal.ninja2020.components.message')
 | 
				
			||||||
 | 
					            {!! CustomMessage::client($client)
 | 
				
			||||||
 | 
					                ->company($client->company)
 | 
				
			||||||
 | 
					                ->entity($invoice)
 | 
				
			||||||
 | 
					                ->message($client->getSetting('custom_message_paid_invoice')) !!}
 | 
				
			||||||
 | 
					        @endcomponent
 | 
				
			||||||
 | 
					    @endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @if($invoice->isPayable())
 | 
					    @if($invoice->isPayable())
 | 
				
			||||||
        <form action="{{ route('client.invoices.bulk') }}" method="post">
 | 
					        <form action="{{ route('client.invoices.bulk') }}" method="post">
 | 
				
			||||||
            @csrf
 | 
					            @csrf
 | 
				
			||||||
 | 
				
			|||||||
@ -12,6 +12,15 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
@section('body')
 | 
					@section('body')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @if(!$quote->isApproved() && !empty($client->getSetting('custom_message_unapproved_quote')))
 | 
				
			||||||
 | 
					        @component('portal.ninja2020.components.message')
 | 
				
			||||||
 | 
					            {!! CustomMessage::client($client)
 | 
				
			||||||
 | 
					                ->company($client->company)
 | 
				
			||||||
 | 
					                ->entity($quote)
 | 
				
			||||||
 | 
					                ->message($client->getSetting('custom_message_unapproved_quote')) !!}
 | 
				
			||||||
 | 
					        @endcomponent
 | 
				
			||||||
 | 
					    @endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @if(!$quote->isApproved())
 | 
					    @if(!$quote->isApproved())
 | 
				
			||||||
        <form action="{{ route('client.quotes.bulk') }}" method="post">
 | 
					        <form action="{{ route('client.quotes.bulk') }}" method="post">
 | 
				
			||||||
            @csrf
 | 
					            @csrf
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user