Setup account linking acceptance view
This commit is contained in:
@@ -335,7 +335,17 @@ class SettingsController extends Controller
|
|||||||
return redirect()->route('settings.subscriptions.index');
|
return redirect()->route('settings.subscriptions.index');
|
||||||
}
|
}
|
||||||
|
|
||||||
return view('settings.users.link');
|
// Get invitations sent by current user's account
|
||||||
|
$sentInvitations = auth()->user()->account->accountLinks()
|
||||||
|
->with(['user', 'invitedBy'])
|
||||||
|
->get();
|
||||||
|
|
||||||
|
// Get invitations received by current user
|
||||||
|
$receivedInvitations = AccountLink::where('user_id', auth()->user()->id)
|
||||||
|
->with(['account', 'invitedBy'])
|
||||||
|
->get();
|
||||||
|
|
||||||
|
return view('settings.users.link', compact('sentInvitations', 'receivedInvitations'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Vendored
+1
@@ -327,6 +327,7 @@ common.loadLanguage(window.Laravel.locale, true).then((i18n) => {
|
|||||||
locale: i18n.locale,
|
locale: i18n.locale,
|
||||||
reminders_frequency: 'once',
|
reminders_frequency: 'once',
|
||||||
accept_invite_user: false,
|
accept_invite_user: false,
|
||||||
|
accept_link_user: false,
|
||||||
date_met_the_contact: 'known',
|
date_met_the_contact: 'known',
|
||||||
global_relationship_form_new_contact: true,
|
global_relationship_form_new_contact: true,
|
||||||
global_profile_default_view: window.Laravel.profileDefaultView,
|
global_profile_default_view: window.Laravel.profileDefaultView,
|
||||||
|
|||||||
@@ -50,4 +50,11 @@ return [
|
|||||||
'export_description' => 'You requested a data export on :date. It is now ready to download.',
|
'export_description' => 'You requested a data export on :date. It is now ready to download.',
|
||||||
'export_download' => 'Download export',
|
'export_download' => 'Download export',
|
||||||
|
|
||||||
|
'account_link_title' => 'Monica – Account Link Invitation from :name',
|
||||||
|
'account_link_intro' => ':name (:email) has invited you to link your Monica account with theirs.',
|
||||||
|
'account_link_explanation' => 'By accepting this invitation, both accounts will share the same contact data and CRM information. You will be able to access and manage the same contacts, relationships, and data.',
|
||||||
|
'account_link_link' => 'To accept the account link invitation, click on the link below:',
|
||||||
|
'account_link_button' => 'Accept Account Link',
|
||||||
|
'account_link_expiration' => 'This link will expire in :count days.',
|
||||||
|
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -197,6 +197,45 @@ return [
|
|||||||
'users_list_delete_confirmation' => 'Are you sure to delete this user from your account?',
|
'users_list_delete_confirmation' => 'Are you sure to delete this user from your account?',
|
||||||
'users_invitation_need_subscription' => 'Adding more users requires a subscription.',
|
'users_invitation_need_subscription' => 'Adding more users requires a subscription.',
|
||||||
|
|
||||||
|
// Account linking
|
||||||
|
'users_list_link_user' => 'Link existing user',
|
||||||
|
'users_link_breadcrumb' => 'Link existing user',
|
||||||
|
'users_link_title' => 'Link an existing Monica user to your account',
|
||||||
|
'users_link_description' => 'Invite an existing Monica user to link their account with yours. Both accounts will share the same contact data and CRM information.',
|
||||||
|
'users_link_email_field' => 'Enter the email of the existing Monica user',
|
||||||
|
'users_link_submit' => 'Send invitation',
|
||||||
|
'users_link_pending_title' => 'Pending account link invitations',
|
||||||
|
'users_link_pending_description' => 'These are account link invitations you\'ve sent that haven\'t been accepted yet.',
|
||||||
|
'users_link_no_pending' => 'No pending account link invitations.',
|
||||||
|
'users_link_invited_by' => 'Invited by :user',
|
||||||
|
'users_link_invited_on' => 'Sent on :date',
|
||||||
|
'users_link_cancel_confirm' => 'Are you sure you want to cancel this account link invitation?',
|
||||||
|
'users_link_confirmation' => 'Please confirm that you want to invite this user before proceeding with the invitation',
|
||||||
|
'users_link_sent_title' => 'Invitations you\'ve sent',
|
||||||
|
'users_link_sent_description' => 'Account link invitations you\'ve sent that are awaiting response.',
|
||||||
|
'users_link_received_title' => 'Invitations you\'ve received',
|
||||||
|
'users_link_received_description' => 'Account link invitations others have sent to you.',
|
||||||
|
'users_link_no_sent' => 'No outgoing invitations.',
|
||||||
|
'users_link_no_received' => 'No incoming invitations.',
|
||||||
|
'users_link_status_pending' => 'Pending',
|
||||||
|
'users_link_status_awaiting_response' => 'Awaiting your response',
|
||||||
|
'account_link_decline_confirm' => 'Are you sure you want to decline this invitation?',
|
||||||
|
|
||||||
|
'account_link_title' => 'Link Your Account',
|
||||||
|
'account_link_invitation_from' => 'Invitation from :name',
|
||||||
|
'account_link_invitation_description' => 'You have been invited to link your Monica account with account #:account. If you accept, both accounts will share the same contact data.',
|
||||||
|
'account_link_what_happens_title' => 'What happens when you accept:',
|
||||||
|
'account_link_what_happens_1' => 'Your current account data will be merged with the inviter\'s account',
|
||||||
|
'account_link_what_happens_2' => 'You will have access to all contacts and data in the linked account',
|
||||||
|
'account_link_what_happens_3' => 'This action cannot be undone',
|
||||||
|
'account_link_accept' => 'Accept invitation',
|
||||||
|
'account_link_decline' => 'Decline',
|
||||||
|
'account_link_back_to_dashboard' => 'Back to dashboard',
|
||||||
|
'account_link_login_required' => 'Please login to accept this account link invitation.',
|
||||||
|
'account_link_wrong_user' => 'This invitation is not for your account.',
|
||||||
|
'account_link_success' => 'Account successfully linked! You now have access to the shared account data.',
|
||||||
|
'account_link_declined' => 'Account link invitation declined.',
|
||||||
|
|
||||||
'subscriptions_account_current_plan' => 'Your current plan',
|
'subscriptions_account_current_plan' => 'Your current plan',
|
||||||
'subscriptions_account_current_legacy' => 'Current plan, not selectable anymore:',
|
'subscriptions_account_current_legacy' => 'Current plan, not selectable anymore:',
|
||||||
'subscriptions_account_current_paid_plan' => 'You are on the :name plan. Thanks so much for being a subscriber.',
|
'subscriptions_account_current_paid_plan' => 'You are on the :name plan. Thanks so much for being a subscriber.',
|
||||||
|
|||||||
@@ -0,0 +1,61 @@
|
|||||||
|
@extends('marketing.skeleton')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<body class="marketing register">
|
||||||
|
<div class="container">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-md-6 offset-md-3 offset-md-3-right">
|
||||||
|
|
||||||
|
<div class="signup-box">
|
||||||
|
<div class="dt w-100">
|
||||||
|
<div class="dtc tc">
|
||||||
|
<img src="{{ asset('img/monica.svg') }}" width="97" height="88" alt="">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h2>{{ trans('settings.account_link_title') }}</h2>
|
||||||
|
|
||||||
|
@include ('partials.errors')
|
||||||
|
|
||||||
|
<div class="alert alert-info">
|
||||||
|
<strong>{{ trans('settings.account_link_invitation_from', ['name' => $accountLink->invitedBy->first_name]) }}</strong>
|
||||||
|
<p class="mb-0 mt-2">{{ trans('settings.account_link_invitation_description', ['account' => $accountLink->account->id]) }}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-body">
|
||||||
|
<h5>{{ trans('settings.account_link_what_happens_title') }}</h5>
|
||||||
|
<ul class="mb-0">
|
||||||
|
<li>{{ trans('settings.account_link_what_happens_1') }}</li>
|
||||||
|
<li>{{ trans('settings.account_link_what_happens_2') }}</li>
|
||||||
|
<li>{{ trans('settings.account_link_what_happens_3') }}</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group actions mt-4">
|
||||||
|
<form method="POST" action="{{ route('account-links.send', $key) }}" style="display: inline-block; width: 48%; margin-right: 4%;">
|
||||||
|
@csrf
|
||||||
|
{{-- Security field to verify inviter's email --}}
|
||||||
|
<input type="hidden" name="email_security" value="{{ $accountLink->invitedBy->email }}">
|
||||||
|
<button type="submit" class="btn btn-primary btn-block">{{ trans('settings.account_link_accept') }}</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<form method="POST" action="{{ route('account-links.decline', $key) }}" style="display: inline-block; width: 48%;">
|
||||||
|
@csrf
|
||||||
|
@method('DELETE')
|
||||||
|
<button type="submit" class="btn btn-outline-secondary btn-block">{{ trans('settings.account_link_decline') }}</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group links mt-4">
|
||||||
|
<ul>
|
||||||
|
<li><a href="{{ route('dashboard.index') }}">{{ trans('settings.account_link_back_to_dashboard') }}</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
@endsection
|
||||||
@@ -43,7 +43,11 @@
|
|||||||
|
|
||||||
<p>{{ trans('settings.users_blank_description') }}</p>
|
<p>{{ trans('settings.users_blank_description') }}</p>
|
||||||
|
|
||||||
<p class="cta"><a href="{{ route('settings.users.create') }}" class="btn">{{ trans('settings.users_blank_cta') }}</a></p>
|
<p class="cta">
|
||||||
|
<a href="{{ route('settings.users.create') }}" class="btn">{{ trans('settings.users_blank_cta') }}</a>
|
||||||
|
<span class="ml-2">{{ trans('app.or') }}</span>
|
||||||
|
<a href="{{ route('settings.users.link.create') }}" class="btn btn-outline-primary ml-2">{{ trans('settings.users_list_link_user') }}</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
@if (config('monica.requires_subscription') && $accountHasLimitations)
|
@if (config('monica.requires_subscription') && $accountHasLimitations)
|
||||||
<p class="requires-subscription">{{ trans('settings.users_invitation_need_subscription') }}</p>
|
<p class="requires-subscription">{{ trans('settings.users_invitation_need_subscription') }}</p>
|
||||||
|
|||||||
@@ -36,7 +36,10 @@
|
|||||||
<div class="pa3 bb b--gray-monica">
|
<div class="pa3 bb b--gray-monica">
|
||||||
<h3 class="with-actions">
|
<h3 class="with-actions">
|
||||||
{{ trans('settings.users_list_title') }}
|
{{ trans('settings.users_list_title') }}
|
||||||
<a href="{{ route('settings.users.create') }}" class="btn">{{ trans('settings.users_list_add_user') }}</a>
|
<div class="actions-list">
|
||||||
|
<a href="{{ route('settings.users.create') }}" class="btn">{{ trans('settings.users_list_add_user') }}</a>
|
||||||
|
<a href="{{ route('settings.users.link.create') }}" class="btn btn-outline-primary ml-2">{{ trans('settings.users_list_link_user') }}</a>
|
||||||
|
</div>
|
||||||
</h3>
|
</h3>
|
||||||
<ul class="table">
|
<ul class="table">
|
||||||
@foreach ($users as $user)
|
@foreach ($users as $user)
|
||||||
|
|||||||
@@ -0,0 +1,151 @@
|
|||||||
|
@extends('layouts.skeleton')
|
||||||
|
|
||||||
|
@section('content')
|
||||||
|
<div class="settings">
|
||||||
|
|
||||||
|
{{-- Breadcrumb --}}
|
||||||
|
<div class="breadcrumb">
|
||||||
|
<div class="{{ Auth::user()->getFluidLayout() }}">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12">
|
||||||
|
<ul class="horizontal">
|
||||||
|
<li>
|
||||||
|
<a href="{{ route('dashboard.index') }}">{{ trans('app.breadcrumb_dashboard') }}</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ route('settings.index') }}">{{ trans('app.breadcrumb_settings') }}</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="{{ route('settings.users.index') }}">{{ trans('app.breadcrumb_settings_users') }}</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
{{ trans('settings.users_link_breadcrumb') }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Page content -->
|
||||||
|
<div class="main-content central-form">
|
||||||
|
<div class="{{ Auth::user()->getFluidLayout() }}">
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-sm-6 offset-sm-3 offset-sm-3-right">
|
||||||
|
<div class="br3 ba b--gray-monica bg-white mb4">
|
||||||
|
<div class="pa3 bb b--gray-monica">
|
||||||
|
<form id="linkForm" method="POST" action="{{ route('settings.users.link.store') }}">
|
||||||
|
@csrf
|
||||||
|
|
||||||
|
<h2>{{ trans('settings.users_link_title') }}</h2>
|
||||||
|
|
||||||
|
<p>{{ trans('settings.users_link_description') }}</p>
|
||||||
|
|
||||||
|
@include('partials.errors')
|
||||||
|
|
||||||
|
{{-- Email --}}
|
||||||
|
<fieldset class="form-group">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="email">{{ trans('settings.users_link_email_field') }}</label>
|
||||||
|
<input type="email" class="form-control" name="email" value="{{ old('email') }}" required autofocus>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
{{-- Explicit confirmation --}}
|
||||||
|
<div class="form-group">
|
||||||
|
<div class="form-check">
|
||||||
|
<input type="checkbox" class="form-check-input" id="confirmation" name="confirmation" value="1" required>
|
||||||
|
<label class="form-check-label" for="confirmation">
|
||||||
|
{{ trans('settings.users_link_confirmation') }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Submit button inside form --}}
|
||||||
|
<div class="form-group">
|
||||||
|
<button type="submit" class="btn btn-primary">{{ trans('settings.users_link_submit') }}</button>
|
||||||
|
<a href="{{ route('settings.users.index') }}" class="btn btn-secondary">{{ trans('app.cancel') }}</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Invitations you've sent --}}
|
||||||
|
<div class="br3 ba b--gray-monica bg-white mb4">
|
||||||
|
<div class="pa3 bb b--gray-monica">
|
||||||
|
<h3>{{ trans('settings.users_link_sent_title') }}</h3>
|
||||||
|
<p>{{ trans('settings.users_link_sent_description') }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="pa3">
|
||||||
|
@if($sentInvitations->count() > 0)
|
||||||
|
<ul class="list-group">
|
||||||
|
@foreach($sentInvitations as $link)
|
||||||
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
|
<div>
|
||||||
|
<strong>{{ $link->user->email }}</strong>
|
||||||
|
<small class="text-muted d-block">{{ trans('settings.users_link_invited_on', ['date' => $link->created_at->format('M j, Y')]) }}</small>
|
||||||
|
<span class="badge badge-warning">{{ trans('settings.users_link_status_pending') }}</span>
|
||||||
|
</div>
|
||||||
|
<form method="POST" action="{{ route('settings.users.link.delete', $link) }}" style="display: inline;">
|
||||||
|
@csrf
|
||||||
|
@method('DELETE')
|
||||||
|
<button type="submit" class="btn btn-sm btn-outline-danger" onclick="return confirm('{{ trans('settings.users_link_cancel_confirm') }}')">
|
||||||
|
{{ trans('app.cancel') }}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</li>
|
||||||
|
@endforeach
|
||||||
|
</ul>
|
||||||
|
@else
|
||||||
|
<p class="text-muted">{{ trans('settings.users_link_no_sent') }}</p>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{-- Invitations you've received --}}
|
||||||
|
<div class="br3 ba b--gray-monica bg-white mb4">
|
||||||
|
<div class="pa3 bb b--gray-monica">
|
||||||
|
<h3>{{ trans('settings.users_link_received_title') }}</h3>
|
||||||
|
<p>{{ trans('settings.users_link_received_description') }}</p>
|
||||||
|
</div>
|
||||||
|
<div class="pa3">
|
||||||
|
@if($receivedInvitations->count() > 0)
|
||||||
|
<ul class="list-group">
|
||||||
|
@foreach($receivedInvitations as $link)
|
||||||
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
|
<div>
|
||||||
|
<strong>{{ trans('settings.account_link_invitation_from', ['name' => $link->invitedBy->first_name]) }}</strong>
|
||||||
|
<small class="text-muted d-block">{{ $link->invitedBy->email }}</small>
|
||||||
|
<small class="text-muted">{{ trans('settings.users_link_invited_on', ['date' => $link->created_at->format('M j, Y')]) }}</small>
|
||||||
|
<span class="badge badge-info">{{ trans('settings.users_link_status_awaiting_response') }}</span>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<a href="{{ route('account-links.accept', $link->invitation_key) }}" class="btn btn-sm btn-success mr-1">
|
||||||
|
{{ trans('settings.account_link_accept') }}
|
||||||
|
</a>
|
||||||
|
<form method="POST" action="{{ route('account-links.decline', $link->invitation_key) }}" style="display: inline;">
|
||||||
|
@csrf
|
||||||
|
@method('DELETE')
|
||||||
|
<button type="submit" class="btn btn-sm btn-outline-danger" onclick="return confirm('{{ trans('settings.account_link_decline_confirm') }}')">
|
||||||
|
{{ trans('settings.account_link_decline') }}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
@endforeach
|
||||||
|
</ul>
|
||||||
|
@else
|
||||||
|
<p class="text-muted">{{ trans('settings.users_link_no_received') }}</p>
|
||||||
|
@endif
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
@endsection
|
||||||
+15
-10
@@ -126,6 +126,15 @@ RUN set -ex; \
|
|||||||
\
|
\
|
||||||
echo 'memory_limit=512M' > $PHP_INI_DIR/conf.d/memory-limit.ini
|
echo 'memory_limit=512M' > $PHP_INI_DIR/conf.d/memory-limit.ini
|
||||||
|
|
||||||
|
# Install Node.js early to leverage Docker layer caching
|
||||||
|
RUN set -ex; \
|
||||||
|
\
|
||||||
|
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -; \
|
||||||
|
apt-get install -y nodejs; \
|
||||||
|
npm install -g yarn; \
|
||||||
|
\
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
RUN set -ex; \
|
RUN set -ex; \
|
||||||
\
|
\
|
||||||
a2enmod headers rewrite remoteip; \
|
a2enmod headers rewrite remoteip; \
|
||||||
@@ -144,7 +153,6 @@ RUN set -ex; \
|
|||||||
|
|
||||||
WORKDIR /var/www/html
|
WORKDIR /var/www/html
|
||||||
|
|
||||||
|
|
||||||
# Copy the local (outside Docker) source into the working directory,
|
# Copy the local (outside Docker) source into the working directory,
|
||||||
# copy system files into their proper homes, and set file ownership
|
# copy system files into their proper homes, and set file ownership
|
||||||
# correctly
|
# correctly
|
||||||
@@ -171,7 +179,7 @@ RUN set -ex; \
|
|||||||
php composer-setup.php --quiet --install-dir=/usr/local/bin --filename=composer; \
|
php composer-setup.php --quiet --install-dir=/usr/local/bin --filename=composer; \
|
||||||
rm composer-setup.php
|
rm composer-setup.php
|
||||||
|
|
||||||
# Install composer dependencies
|
# Install PHP dependencies
|
||||||
RUN set -ex; \
|
RUN set -ex; \
|
||||||
\
|
\
|
||||||
mkdir -p storage/framework/views; \
|
mkdir -p storage/framework/views; \
|
||||||
@@ -179,16 +187,13 @@ RUN set -ex; \
|
|||||||
composer clear-cache; \
|
composer clear-cache; \
|
||||||
rm -rf .composer
|
rm -rf .composer
|
||||||
|
|
||||||
# Install node dependencies
|
# Install Node.js dependencies and build assets
|
||||||
RUN set -ex; \
|
RUN set -ex; \
|
||||||
\
|
\
|
||||||
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -; \
|
yarn install --production=false; \
|
||||||
apt-get install -y nodejs; \
|
yarn run production
|
||||||
npm install -g yarn; \
|
|
||||||
yarn run inst; \
|
|
||||||
yarn run production; \
|
|
||||||
\
|
|
||||||
rm -rf /var/lib/apt/lists/*
|
|
||||||
|
|
||||||
COPY scripts/docker/entrypoint.sh \
|
COPY scripts/docker/entrypoint.sh \
|
||||||
scripts/docker/cron.sh \
|
scripts/docker/cron.sh \
|
||||||
|
|||||||
Reference in New Issue
Block a user