adjust templates, add timezone and locale
This commit is contained in:
@@ -21,6 +21,7 @@ gem 'pg'
|
||||
gem 'premailer-rails'
|
||||
gem 'puma'
|
||||
gem 'rails'
|
||||
gem 'rails-i18n'
|
||||
gem 'ruby-vips'
|
||||
gem 'shakapacker'
|
||||
gem 'sqlite3'
|
||||
|
||||
@@ -352,6 +352,9 @@ GEM
|
||||
rails-html-sanitizer (1.6.0)
|
||||
loofah (~> 2.21)
|
||||
nokogiri (~> 1.14)
|
||||
rails-i18n (7.0.7)
|
||||
i18n (>= 0.7, < 2)
|
||||
railties (>= 6.0.0, < 8)
|
||||
railties (7.0.5)
|
||||
actionpack (= 7.0.5)
|
||||
activesupport (= 7.0.5)
|
||||
@@ -511,6 +514,7 @@ DEPENDENCIES
|
||||
pry-rails
|
||||
puma
|
||||
rails
|
||||
rails-i18n
|
||||
rspec-rails
|
||||
rubocop
|
||||
rubocop-performance
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class AccountsController < ApplicationController
|
||||
LOCALE_OPTIONS = {
|
||||
'en-US' => 'English (United States)',
|
||||
'en-GB' => 'English (United Kingdom)',
|
||||
'es-ES' => 'Spanish (Spain)',
|
||||
'pt-PT' => 'Portuguese (Portugal)',
|
||||
'de-DE' => 'German (Germany)'
|
||||
}.freeze
|
||||
|
||||
def show; end
|
||||
|
||||
def update
|
||||
current_account.update!(account_params)
|
||||
|
||||
@encrypted_config = EncryptedConfig.find_or_initialize_by(account: current_account,
|
||||
key: EncryptedConfig::APP_URL_KEY)
|
||||
@encrypted_config.update!(app_url_params)
|
||||
|
||||
Docuseal.refresh_default_url_options!
|
||||
|
||||
redirect_to settings_account_path, notice: 'Account information has been updated'
|
||||
rescue ActiveRecord::RecordInvalid
|
||||
render :show, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def account_params
|
||||
params.require(:account).permit(:name, :timezone, :locale)
|
||||
end
|
||||
|
||||
def app_url_params
|
||||
params.require(:encrypted_config).permit(:value)
|
||||
end
|
||||
end
|
||||
@@ -1,13 +1,11 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
class ProfileController < ApplicationController
|
||||
before_action :load_encrypted_config, only: %i[index update_app_url]
|
||||
|
||||
def index; end
|
||||
|
||||
def update_contact
|
||||
if current_user.update(contact_params)
|
||||
redirect_to settings_profile_index_path, notice: 'Contact information successfully updated'
|
||||
redirect_to settings_profile_index_path, notice: 'Contact information has been updated'
|
||||
else
|
||||
render :index, status: :unprocessable_entity
|
||||
end
|
||||
@@ -16,17 +14,7 @@ class ProfileController < ApplicationController
|
||||
def update_password
|
||||
if current_user.update(password_params)
|
||||
bypass_sign_in(current_user)
|
||||
redirect_to settings_profile_index_path, notice: 'Password successfully changed'
|
||||
else
|
||||
render :index, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def update_app_url
|
||||
if @encrypted_config.update(app_url_params)
|
||||
Docuseal.refresh_default_url_options!
|
||||
|
||||
redirect_to settings_profile_index_path, notice: 'App URL successfully changed'
|
||||
redirect_to settings_profile_index_path, notice: 'Password has been changed'
|
||||
else
|
||||
render :index, status: :unprocessable_entity
|
||||
end
|
||||
@@ -34,20 +22,11 @@ class ProfileController < ApplicationController
|
||||
|
||||
private
|
||||
|
||||
def load_encrypted_config
|
||||
@encrypted_config =
|
||||
EncryptedConfig.find_or_initialize_by(account: current_account, key: EncryptedConfig::APP_URL_KEY)
|
||||
end
|
||||
|
||||
def contact_params
|
||||
params.require(:user).permit(:first_name, :last_name, :email, account_attributes: %i[name])
|
||||
params.require(:user).permit(:first_name, :last_name, :email)
|
||||
end
|
||||
|
||||
def password_params
|
||||
params.require(:user).permit(:password, :password_confirmation)
|
||||
end
|
||||
|
||||
def app_url_params
|
||||
params.require(:encrypted_config).permit(:value)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -5,6 +5,7 @@ class RegistrationsController < Devise::RegistrationsController
|
||||
|
||||
def build_resource(_hash = {})
|
||||
account = Account.new(account_params)
|
||||
account.timezone = Accounts.normalize_timezone(account.timezone)
|
||||
|
||||
self.resource = account.users.new(user_params)
|
||||
end
|
||||
@@ -18,6 +19,6 @@ class RegistrationsController < Devise::RegistrationsController
|
||||
def account_params
|
||||
return {} if params[:account].blank?
|
||||
|
||||
params.require(:account).permit(:name)
|
||||
params.require(:account).permit(:name, :timezone)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -15,6 +15,8 @@ class SetupController < ApplicationController
|
||||
|
||||
def create
|
||||
@account = Account.new(account_params)
|
||||
@account.timezone = Accounts.normalize_timezone(@account.timezone)
|
||||
|
||||
@user = @account.users.new(user_params)
|
||||
|
||||
if @user.save
|
||||
@@ -24,6 +26,8 @@ class SetupController < ApplicationController
|
||||
]
|
||||
@account.encrypted_configs.create!(encrypted_configs)
|
||||
|
||||
Docuseal.refresh_default_url_options!
|
||||
|
||||
sign_in(@user)
|
||||
|
||||
redirect_to root_path
|
||||
@@ -43,7 +47,7 @@ class SetupController < ApplicationController
|
||||
def account_params
|
||||
return {} unless params[:account]
|
||||
|
||||
params.require(:account).permit(:name)
|
||||
params.require(:account).permit(:name, :timezone)
|
||||
end
|
||||
|
||||
def encrypted_config_params
|
||||
|
||||
@@ -16,7 +16,7 @@ class StartFormController < ApplicationController
|
||||
.find_or_initialize_by(**submitter_params)
|
||||
|
||||
if @submitter.completed_at?
|
||||
redirect_to start_form_completed_path(@template.slug, email: submission_params[:email])
|
||||
redirect_to start_form_completed_path(@template.slug, email: submitter_params[:email])
|
||||
else
|
||||
@submitter.assign_attributes(
|
||||
uuid: @template.submitters.first['uuid'],
|
||||
@@ -36,7 +36,7 @@ class StartFormController < ApplicationController
|
||||
end
|
||||
|
||||
def completed
|
||||
@submitter = Submitter.where(submission: @template.submitters).find_by(email: params[:email])
|
||||
@submitter = Submitter.where(submission: @template.submissions).find_by!(email: params[:email])
|
||||
end
|
||||
|
||||
private
|
||||
@@ -46,7 +46,7 @@ class StartFormController < ApplicationController
|
||||
end
|
||||
|
||||
def load_template
|
||||
slug = params[:slug] || params[:start_template_slug]
|
||||
slug = params[:slug] || params[:start_form_slug]
|
||||
|
||||
@template = Template.find_by!(slug:)
|
||||
end
|
||||
|
||||
@@ -19,6 +19,7 @@ class SubmitFormController < ApplicationController
|
||||
submitter = Submitter.find_by!(slug: params[:slug])
|
||||
submitter.values.merge!(normalized_values)
|
||||
submitter.completed_at = Time.current if params[:completed] == 'true'
|
||||
submitter.opened_at ||= Time.current
|
||||
|
||||
submitter.save!
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ import ClipboardCopy from './elements/clipboard_copy'
|
||||
import DynamicList from './elements/dynamic_list'
|
||||
import DownloadButton from './elements/download_button'
|
||||
import SetOriginUrl from './elements/set_origin_url'
|
||||
import SetTimezone from './elements/set_timezone'
|
||||
|
||||
document.addEventListener('turbo:before-cache', () => {
|
||||
window.flash?.remove()
|
||||
@@ -32,6 +33,7 @@ window.customElements.define('clipboard-copy', ClipboardCopy)
|
||||
window.customElements.define('dynamic-list', DynamicList)
|
||||
window.customElements.define('download-button', DownloadButton)
|
||||
window.customElements.define('set-origin-url', SetOriginUrl)
|
||||
window.customElements.define('set-timezone', SetTimezone)
|
||||
|
||||
window.customElements.define('template-builder', class extends HTMLElement {
|
||||
connectedCallback () {
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
export default class extends HTMLElement {
|
||||
connectedCallback () {
|
||||
if (this.dataset.inputId) {
|
||||
document.getElementById(this.dataset.inputId).value = Intl.DateTimeFormat().resolvedOptions().timeZone
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -207,7 +207,7 @@ export default {
|
||||
},
|
||||
formattedDate () {
|
||||
if (this.field.type === 'date' && this.modelValue) {
|
||||
return new Intl.DateTimeFormat({ year: 'numeric', month: 'numeric', day: 'numeric' }).format(new Date(this.modelValue))
|
||||
return new Intl.DateTimeFormat([], { year: 'numeric', month: 'long', day: 'numeric' }).format(new Date(this.modelValue))
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
|
||||
@@ -41,6 +41,10 @@
|
||||
>{{ currentField.name }}
|
||||
<template v-if="!currentField.required">(optional)</template>
|
||||
</label>
|
||||
<div
|
||||
v-else
|
||||
class="py-1"
|
||||
/>
|
||||
<div>
|
||||
<input
|
||||
:id="currentField.uuid"
|
||||
@@ -62,6 +66,10 @@
|
||||
>{{ currentField.name }}
|
||||
<template v-if="!currentField.required">(optional)</template>
|
||||
</label>
|
||||
<div
|
||||
v-else
|
||||
class="py-1"
|
||||
/>
|
||||
<div class="text-center">
|
||||
<input
|
||||
:id="currentField.uuid"
|
||||
@@ -82,6 +90,10 @@
|
||||
>{{ currentField.name }}
|
||||
<template v-if="!currentField.required">(optional)</template>
|
||||
</label>
|
||||
<div
|
||||
v-else
|
||||
class="py-1"
|
||||
/>
|
||||
<select
|
||||
:id="currentField.uuid"
|
||||
:required="currentField.required"
|
||||
@@ -246,7 +258,7 @@
|
||||
:key="step[0].uuid"
|
||||
href="#"
|
||||
class="inline border border-base-300 h-3 w-3 rounded-full mx-1"
|
||||
:class="{ 'bg-base-200': index === currentStep, 'bg-base-content': index < currentStep || isCompleted, 'bg-white': index > currentStep }"
|
||||
:class="{ 'bg-base-300': index === currentStep, 'bg-base-content': index < currentStep || isCompleted, 'bg-white': index > currentStep }"
|
||||
@click.prevent="isCompleted ? '' : goToStep(step, true)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
# Table name: accounts
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# locale :string not null
|
||||
# name :string not null
|
||||
# timezone :string not null
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
@@ -15,4 +17,7 @@ class Account < ApplicationRecord
|
||||
has_many :templates, dependent: :destroy
|
||||
has_many :active_users, -> { active }, dependent: :destroy,
|
||||
inverse_of: :account, class_name: 'User'
|
||||
|
||||
attribute :timezone, :string, default: 'UTC'
|
||||
attribute :locale, :string, default: 'en-US'
|
||||
end
|
||||
|
||||
@@ -50,4 +50,8 @@ class Submitter < ApplicationRecord
|
||||
'awaiting'
|
||||
end
|
||||
end
|
||||
|
||||
def status_event_at
|
||||
completed_at || opened_at || sent_at || created_at
|
||||
end
|
||||
end
|
||||
|
||||
@@ -52,8 +52,6 @@ class User < ApplicationRecord
|
||||
|
||||
scope :active, -> { where(deleted_at: nil) }
|
||||
|
||||
accepts_nested_attributes_for :account, update_only: true
|
||||
|
||||
def active_for_authentication?
|
||||
!deleted_at?
|
||||
end
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
<div class="flex flex-wrap space-y-4 md:flex-nowrap md:space-y-0">
|
||||
<%= render 'shared/settings_nav' %>
|
||||
<div class="flex-grow max-w-xl mx-auto">
|
||||
<h1 class="text-4xl font-bold mb-4">Account</h1>
|
||||
<%= form_for '', url: settings_account_path, method: :patch, html: { autocomplete: 'off', class: 'space-y-4' } do |f| %>
|
||||
<%= f.fields_for current_account do |ff| %>
|
||||
<div class="form-control">
|
||||
<%= ff.label :name, 'Company Name', class: 'label' %>
|
||||
<%= ff.text_field :name, required: true, class: 'base-input' %>
|
||||
</div>
|
||||
<div class="grid md:grid-cols-2 gap-4">
|
||||
<div class="form-control">
|
||||
<%= ff.label :timezone, class: 'label' %>
|
||||
<%= ff.select :timezone, nil, {}, class: 'select base-input w-full font-normal' do %>
|
||||
<%= time_zone_options_for_select(current_account.timezone) %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<%= ff.label :locale, 'Time format', class: 'label' %>
|
||||
<%= ff.select :locale, options_for_select(controller.class::LOCALE_OPTIONS.invert, current_account.locale), {}, class: 'select base-input w-full font-normal' %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= f.fields_for @encrypted_config || EncryptedConfig.find_or_initialize_by(account: current_account, key: EncryptedConfig::APP_URL_KEY) do |ff| %>
|
||||
<div class="form-control">
|
||||
<%= ff.label :value, 'App URL', class: 'label' %>
|
||||
<%= ff.text_field :value, autocomplete: 'off', class: 'base-input' %>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="form-control pt-2">
|
||||
<%= f.button button_title(title: 'Update', disabled_with: 'Updating'), class: 'base-button' %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="w-0 md:w-52"></div>
|
||||
</div>
|
||||
@@ -20,7 +20,7 @@
|
||||
</p>
|
||||
<p class="flex items-center space-x-1 text-xs text-base-content/60">
|
||||
<%= svg_icon('calendar', class: 'w-4 h-4') %>
|
||||
<span><%= l(template.created_at, format: :long) %></span>
|
||||
<span><%= l(template.created_at.in_time_zone(current_account.timezone), format: :short, locale: current_account.locale) %></span>
|
||||
</p>
|
||||
</div>
|
||||
</a>
|
||||
@@ -39,18 +39,22 @@
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<%= render 'shared/pagination', pagy: @pagy, items_name: 'Templates' %>
|
||||
<%= render 'shared/pagination', pagy: @pagy, items_name: 'templates' %>
|
||||
<% else %>
|
||||
<div class="card bg-base-200 h-96 mb-2">
|
||||
<div class="card-body text-center">
|
||||
<div class="flex items-center h-full">
|
||||
<div class="max-w-lg mx-auto">
|
||||
<h1 class="text-5xl font-bold">Welcome to DocuSeal</h1>
|
||||
<p class="py-6">Streamline document workflows, from creating customizable templates to filling and signing document forms, with DocuSeal</p>
|
||||
<%= link_to new_template_path, class: 'btn btn-neutral', data: { turbo_frame: :modal } do %>
|
||||
<%= svg_icon('plus', class: 'w-6 h-6') %>
|
||||
<span>Create Template</span>
|
||||
<% end %>
|
||||
<div class="mx-auto">
|
||||
<div class="max-w-xl mx-auto">
|
||||
<h1 class="text-5xl font-bold text-base-content">👋 Welcome to DocuSeal</h1>
|
||||
</div>
|
||||
<div class="max-w-lg mx-auto">
|
||||
<p class="py-6 text-gray-600">Streamline document workflows, from creating customizable templates to filling and signing document forms, with DocuSeal</p>
|
||||
<%= link_to new_template_path, class: 'base-button', data: { turbo_frame: :modal } do %>
|
||||
<%= svg_icon('plus', class: 'w-6 h-6 stroke-2') %>
|
||||
<span>Create Template</span>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,13 +4,21 @@
|
||||
<div class="space-y-2">
|
||||
<%= render 'devise/shared/error_messages', resource: %>
|
||||
<%= f.fields_for resource do |ff| %>
|
||||
<div class="form-control">
|
||||
<%= ff.label :first_name, class: 'label' %>
|
||||
<%= ff.text_field :first_name, required: true, class: 'base-input' %>
|
||||
<div class="grid gap-2 md:grid-cols-2 md:gap-4">
|
||||
<div class="form-control">
|
||||
<%= ff.label :first_name, class: 'label' %>
|
||||
<%= ff.text_field :first_name, required: true, class: 'base-input' %>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<%= ff.label :last_name, class: 'label' %>
|
||||
<%= ff.text_field :last_name, required: true, class: 'base-input' %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= f.fields_for resource do |ff| %>
|
||||
<div class="form-control">
|
||||
<%= ff.label :last_name, class: 'label' %>
|
||||
<%= ff.text_field :last_name, required: true, class: 'base-input' %>
|
||||
<%= ff.label :email, class: 'label' %>
|
||||
<%= ff.email_field :email, required: true, class: 'base-input' %>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= f.fields_for resource.account do |ff| %>
|
||||
@@ -20,10 +28,6 @@
|
||||
</div>
|
||||
<% end %>
|
||||
<%= f.fields_for resource do |ff| %>
|
||||
<div class="form-control">
|
||||
<%= ff.label :email, class: 'label' %>
|
||||
<%= ff.email_field :email, required: true, class: 'base-input' %>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<%= ff.label :password, class: 'label' %>
|
||||
<%= ff.password_field :password, required: true, class: 'base-input' %>
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
<%= render 'shared/settings_nav' %>
|
||||
<div class="flex-grow max-w-xl mx-auto">
|
||||
<h1 class="text-4xl font-bold mb-4">Email SMTP</h1>
|
||||
<p>
|
||||
Configure your to send emails (TODO)
|
||||
</p>
|
||||
<% value = @encrypted_config.value || {} %>
|
||||
<%= form_for @encrypted_config, url: settings_email_index_path, method: :post, html: { autocomplete: 'off', class: 'space-y-4' } do |f| %>
|
||||
<%= f.fields_for :value do |ff| %>
|
||||
@@ -29,11 +26,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<%= ff.label :from_email, 'Send from', class: 'label' %>
|
||||
<%= ff.label :from_email, 'Send from Email', class: 'label' %>
|
||||
<%= ff.email_field :from_email, value: value['from_email'], required: true, class: 'base-input' %>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="form-control">
|
||||
<div class="form-control pt-2">
|
||||
<%= f.button button_title(title: 'Save', disabled_with: 'Saving'), class: 'base-button' %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
@@ -50,7 +50,7 @@
|
||||
</div>
|
||||
<div class="flex items-center space-x-1">
|
||||
<%= svg_icon('calendar', class: 'w-5 h-5 inline') %>
|
||||
<span><%= l(signature.signing_time, format: :long) %></span>
|
||||
<span><%= l(signature.signing_time.in_time_zone(current_account.timezone), format: :long, locale: current_account.locale) %></span>
|
||||
</div>
|
||||
<div class="flex items-center space-x-1">
|
||||
<%= svg_icon('certificate', class: 'w-5 h-5 inline') %>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div class="flex flex-wrap space-y-4 md:flex-nowrap md:space-y-0">
|
||||
<%= render 'shared/settings_nav' %>
|
||||
<div class="flex-grow max-w-xl mx-auto">
|
||||
<h1 class="text-4xl font-bold mb-4">Verify PDF Signature</h1>
|
||||
<h1 class="text-4xl font-bold mb-4">PDF Signature</h1>
|
||||
<div id="result">
|
||||
<p class="mb-2">
|
||||
Upload signed PDF file to validate its signature:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="max-w-xl mx-auto px-2">
|
||||
<h1 class="text-4xl font-bold text-center my-8">Welcome to Docuseal</h1>
|
||||
<h1 class="text-4xl font-bold text-center my-8">👋 Welcome to Docuseal</h1>
|
||||
<%= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put, class: 'space-y-6' }) do |f| %>
|
||||
<div class="space-y-2">
|
||||
<%= render 'devise/shared/error_messages', resource: %>
|
||||
|
||||
@@ -8,65 +8,61 @@
|
||||
DocuSeal
|
||||
</h1>
|
||||
</div>
|
||||
<p class="mb-16 text-lg text-center text-gray-500">
|
||||
A self-hosted, web-based platform providing secure and efficient digital document signing and transaction management.
|
||||
</p>
|
||||
<h2 class="mb-16 text-lg text-center text-gray-500">
|
||||
A self-hosted and open-source web platform that provides secure and efficient digital document signing and processing.
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 gap-12 md:gap-10 md:grid-cols-2">
|
||||
<div class="card bg-base-300">
|
||||
<div class="card bg-base-200">
|
||||
<div class="card-body">
|
||||
<div class="text-center transition-all">
|
||||
<div class="inline-block p-4 mb-6 -mt-16 bg-base-content rounded-full">
|
||||
<div class="inline-block p-4 mb-4 -mt-16 bg-base-content rounded-full">
|
||||
<%= svg_icon('brand_docker', class: 'w-10 h-10 text-base-100 stroke-1') %>
|
||||
</div>
|
||||
<h3 class="mb-4 text-2xl font-semibold">Easy to Install</h3>
|
||||
<h3 class="mb-4 text-2xl font-semibold">Easy to Start</h3>
|
||||
<p class="text-base text-gray-500">
|
||||
Simply initiate the process on your platform, deploy the solution via <a href="https://hub.docker.com/r/docuseal/docuseal" class="link link-neutral font-bold" target="_blank">Docker</a>,
|
||||
or opt for its packaged version for ease of use.
|
||||
Run on your own host using <a href="https://hub.docker.com/r/docuseal/docuseal" class="link link-neutral font-bold" target="_blank">Docker</a> container, or deploy on your favorite managed PaaS with a single <a href="https:///www.docuseal.co/install" class="link link-neutral font-bold">click</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card bg-base-300">
|
||||
<div class="card bg-base-200">
|
||||
<div class="card-body">
|
||||
<div class="text-center transition-all">
|
||||
<div class="inline-block p-4 mb-6 -mt-16 bg-base-content rounded-full">
|
||||
<div class="inline-block p-4 mb-4 -mt-16 bg-base-content rounded-full">
|
||||
<%= svg_icon('devices', class: 'w-10 h-10 text-base-100') %>
|
||||
</div>
|
||||
<h3 class="mb-4 text-2xl font-semibold">Mobile Optimized</h3>
|
||||
<p class="text-base text-gray-500">
|
||||
This self-hosted solution is mobile-ready, designed to offer a seamless user experience on any device.
|
||||
Manage documents with ease, right from your smartphone or tablet.
|
||||
Review and sign digital documents online from any device.
|
||||
Docuseal document forms are optimized for screens of all sizes.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card bg-base-300">
|
||||
<div class="card bg-base-200">
|
||||
<div class="card-body">
|
||||
<div class="text-center transition-all">
|
||||
<div class="inline-block p-4 mb-6 -mt-16 bg-base-content rounded-full">
|
||||
<div class="inline-block p-4 mb-4 -mt-16 bg-base-content rounded-full">
|
||||
<%= svg_icon('shield_check', class: 'w-10 h-10 text-base-100') %>
|
||||
</div>
|
||||
<h3 class="mb-4 text-2xl font-semibold">Secure</h3>
|
||||
<p class="text-base text-gray-500">
|
||||
With a focus on security, this solution integrates top-level encryption within your own hosting infrastructure.
|
||||
Comprehensive tracking of every action assures a secure environment for all digital transactions.
|
||||
Host it on your hardware under a VPN to ensure that important documents can be accesses only within your organization.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card bg-base-300">
|
||||
<div class="card bg-base-200">
|
||||
<div class="card-body">
|
||||
<div class="text-center transition-all">
|
||||
<div class="inline-block p-4 mb-6 -mt-16 bg-base-content rounded-full">
|
||||
<div class="inline-block p-4 mb-4 -mt-16 bg-base-content rounded-full">
|
||||
<%= svg_icon('brand_github', class: 'w-10 h-10 text-base-100') %>
|
||||
</div>
|
||||
<h3 class="mb-4 text-2xl font-semibold">Open Source</h3>
|
||||
<p class="text-base text-gray-500">
|
||||
Don't hesitate to fetch <a href="https://github.com/docusealhq" class="link link-neutral font-bold" target="_blank">github.com/docusealhq</a>.
|
||||
We warmly invite you to participate and help us enhance this project.
|
||||
There's no need to shy away from becoming a contributor!
|
||||
Source code is available under <a href="https://github.com/docusealhq/docuseal" class="link link-neutral font-bold" target="_blank">github.com/docusealhq</a>.<br>Open-source contributors are always ready to help!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
<%= render 'shared/settings_nav' %>
|
||||
<div class="flex-grow max-w-xl mx-auto">
|
||||
<h1 class="text-4xl font-bold mb-4">Profile</h1>
|
||||
<p>
|
||||
Manage your contact information
|
||||
</p>
|
||||
<%= form_for current_user, url: update_contact_settings_profile_index_path, method: :patch, html: { autocomplete: 'off', class: 'space-y-4' } do |f| %>
|
||||
<div class="grid md:grid-cols-2 gap-4">
|
||||
<div class="form-control">
|
||||
@@ -20,13 +17,7 @@
|
||||
<%= f.label :email, 'Email', class: 'label' %>
|
||||
<%= f.email_field :email, autocomplete: 'off', class: 'base-input' %>
|
||||
</div>
|
||||
<%= f.fields_for :account do |ff| %>
|
||||
<div class="form-control">
|
||||
<%= ff.label :name, 'Company Name', class: 'label' %>
|
||||
<%= ff.text_field :name, required: true, class: 'base-input' %>
|
||||
</div>
|
||||
<% end %>
|
||||
<div class="form-control">
|
||||
<div class="form-control pt-2">
|
||||
<%= f.button button_title(title: 'Update', disabled_with: 'Updating'), class: 'base-button' %>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -40,16 +31,7 @@
|
||||
<%= f.label :password_confirmation, 'Confirm new password', class: 'label' %>
|
||||
<%= f.password_field :password_confirmation, autocomplete: 'off', class: 'base-input' %>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<%= f.button button_title(title: 'Update', disabled_with: 'Updating'), class: 'base-button' %>
|
||||
</div>
|
||||
<% end %>
|
||||
<p class="text-2xl font-bold mt-8 mb-4">App URL</p>
|
||||
<%= form_for @encrypted_config, url: update_app_url_settings_profile_index_path, method: :patch, html: { autocomplete: 'off', class: 'space-y-4' } do |f| %>
|
||||
<div class="form-control">
|
||||
<%= f.text_field :value, required: true, class: 'base-input' %>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<div class="form-control pt-2">
|
||||
<%= f.button button_title(title: 'Update', disabled_with: 'Updating'), class: 'base-button' %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
@@ -1 +1,18 @@
|
||||
Email has bee sent
|
||||
<div class="max-w-md mx-auto px-2 mt-12 mb-4">
|
||||
<div class="space-y-6 mx-auto">
|
||||
<div class="space-y-6">
|
||||
<div class="flex items-center justify-center">
|
||||
<a href="/" class="flex items-center">
|
||||
<div class="mr-3">
|
||||
<%= render 'shared/logo', width: '50px', height: '50px' %>
|
||||
</div>
|
||||
<h1 class="text-5xl font-bold text-center">DocuSeal</h1>
|
||||
</a>
|
||||
</div>
|
||||
<div class="text-center text-4xl font-bold">
|
||||
Email has been sent
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<%= render 'shared/attribution' %>
|
||||
|
||||
@@ -14,17 +14,21 @@
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= f.fields_for @user do |ff| %>
|
||||
<div class="form-control">
|
||||
<%= ff.label :email, class: 'label' %>
|
||||
<%= ff.email_field :email, required: true, class: 'base-input' %>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= f.fields_for @account do |ff| %>
|
||||
<set-timezone data-input-id="_account_timezone"></set-timezone>
|
||||
<%= ff.hidden_field :timezone %>
|
||||
<div class="form-control">
|
||||
<%= ff.label :name, 'Company name', class: 'label' %>
|
||||
<%= ff.text_field :name, required: true, class: 'base-input' %>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= f.fields_for @user do |ff| %>
|
||||
<div class="form-control">
|
||||
<%= ff.label :email, class: 'label' %>
|
||||
<%= ff.email_field :email, required: true, class: 'base-input' %>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<%= ff.label :password, class: 'label' %>
|
||||
<%= ff.password_field :password, required: true, placeholder: '************', class: 'base-input' %>
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
<div class="card bg-base-200">
|
||||
<div class="card-body text-center">
|
||||
<div class="max-w-md mx-auto">
|
||||
<p class="text-4xl font-semibold text-gray-700 mb-4">Nothing to display</p>
|
||||
<p class="text-gray-500">We apologize, but currently there is no data available to be displayed. You can try adding new entries or refreshing the page to see if any data becomes available.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -2,7 +2,7 @@
|
||||
<% if @pagy.pages > 1 %>
|
||||
<div class="flex my-6 justify-center md:justify-between">
|
||||
<div class="hidden md:block text-sm">
|
||||
<%= @pagy.from %>-<%= @pagy.to %> of <%= @pagy.count %> of <%= local_assigns[:items_name] || 'items' %>
|
||||
<%= @pagy.from %>-<%= @pagy.to %> of <%= @pagy.count %> <%= local_assigns[:items_name] || 'items' %>
|
||||
</div>
|
||||
<div class="join">
|
||||
<% if @pagy.prev %>
|
||||
|
||||
@@ -6,6 +6,9 @@
|
||||
<li>
|
||||
<%= link_to 'Profile', settings_profile_index_path, class: 'text-base hover:bg-base-300' %>
|
||||
</li>
|
||||
<li>
|
||||
<%= link_to 'Account', settings_account_path, class: 'text-base hover:bg-base-300' %>
|
||||
</li>
|
||||
<li>
|
||||
<%= link_to 'Email', settings_email_index_path, class: 'text-base hover:bg-base-300' %>
|
||||
</li>
|
||||
@@ -13,7 +16,7 @@
|
||||
<%= link_to 'Storage', settings_storage_index_path, class: 'text-base hover:bg-base-300' %>
|
||||
</li>
|
||||
<li>
|
||||
<%= link_to 'eSign', settings_esign_index_path, class: 'text-base hover:bg-base-300' %>
|
||||
<%= link_to 'Signature', settings_esign_index_path, class: 'text-base hover:bg-base-300' %>
|
||||
</li>
|
||||
<li>
|
||||
<%= link_to 'Team', settings_users_path, class: 'text-base hover:bg-base-300' %>
|
||||
|
||||
@@ -1,4 +1,37 @@
|
||||
<p>
|
||||
Form has been submitted already - thanks!
|
||||
</p>
|
||||
<%= button_to button_title(title: 'Send copy to Email', disabled_with: 'Sending'), send_submission_email_index_path, params: { template_slug: @template.slug, email: params[:email] }, form: { onsubmit: 'event.submitter.disabled = true' } %>
|
||||
<div class="max-w-md mx-auto px-2 mt-12 mb-4">
|
||||
<div class="space-y-6 mx-auto">
|
||||
<div class="space-y-6">
|
||||
<div class="flex items-center justify-center">
|
||||
<a href="/" class="flex items-center">
|
||||
<div class="mr-3">
|
||||
<%= render 'shared/logo', width: '50px', height: '50px' %>
|
||||
</div>
|
||||
<h1 class="text-5xl font-bold text-center">DocuSeal</h1>
|
||||
</a>
|
||||
</div>
|
||||
<div class="flex items-center bg-base-300 rounded-xl p-4 mb-4">
|
||||
<div class="flex items-center">
|
||||
<div class="mr-3">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-10 h-10" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M3 19c3.333 -2 5 -4 5 -6c0 -3 -1 -3 -2 -3s-2.032 1.085 -2 3c.034 2.048 1.658 2.877 2.5 4c1.5 2 2.5 2.5 3.5 1c.667 -1 1.167 -1.833 1.5 -2.5c1 2.333 2.333 3.5 4 3.5h2.5" />
|
||||
<path d="M20 17v-12c0 -1.121 -.879 -2 -2 -2s-2 .879 -2 2v12l2 2l2 -2z" />
|
||||
<path d="M16 7h4" />
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-lg font-bold mb-1"><%= @submitter.submission.template.name %></p>
|
||||
<p class="text-sm">Signed on <%= l(@submitter.completed_at.to_date, format: :long, locale: @submitter.submission.template.account.locale) %></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-center text-2xl font-semibold">
|
||||
Form has been submitter already
|
||||
</div>
|
||||
<div>
|
||||
<%= button_to button_title(title: 'Send copy to Email', disabled_with: 'Sending', icon: svg_icon('mail_forward', class: 'w-6 h-6')), send_submission_email_index_path, params: { submitter_slug: @submitter.slug }, form: { onsubmit: 'event.submitter.disabled = true' }, class: 'base-button w-full' %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<%= render 'shared/attribution' %>
|
||||
|
||||
@@ -10,10 +10,10 @@
|
||||
<h1 class="text-5xl font-bold text-center">DocuSeal</h1>
|
||||
</a>
|
||||
<p class="text-xl font-semibold text-center">You have been invited to submit the form</p>
|
||||
<div class="flex items-center bg-neutral rounded-xl p-4">
|
||||
<div class="flex items-center bg-base-content/10 rounded-xl p-4">
|
||||
<div class="flex items-center">
|
||||
<div class="mr-3">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-10 h-10 text-gray-100 " width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-10 h-10" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M3 19c3.333 -2 5 -4 5 -6c0 -3 -1 -3 -2 -3s-2.032 1.085 -2 3c.034 2.048 1.658 2.877 2.5 4c1.5 2 2.5 2.5 3.5 1c.667 -1 1.167 -1.833 1.5 -2.5c1 2.333 2.333 3.5 4 3.5h2.5" />
|
||||
<path d="M20 17v-12c0 -1.121 -.879 -2 -2 -2s-2 .879 -2 2v12l2 2l2 -2z" />
|
||||
@@ -21,8 +21,8 @@
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-gray-100 font-bold mb-1"><%= @template.name %></p>
|
||||
<p class="text-sm text-gray-300">Invited by <%= @template.account.name %></p>
|
||||
<p class="font-bold mb-1"><%= @template.name %></p>
|
||||
<p class="text-sm">Invited by <%= @template.account.name %></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
<%= render 'shared/settings_nav' %>
|
||||
<div class="flex-grow max-w-xl mx-auto">
|
||||
<h1 class="text-4xl font-bold mb-4">Storage</h1>
|
||||
<p class="mb-4">
|
||||
Select files storage option (TODO)
|
||||
</p>
|
||||
<% value = @encrypted_config.value || { 'service' => 'disk' } %>
|
||||
<% configs = value['configs'] || {} %>
|
||||
<%= form_for @encrypted_config, url: settings_storage_index_path, method: :post, html: { autocomplete: 'off', class: 'w-full' } do |f| %>
|
||||
@@ -29,10 +26,10 @@
|
||||
<disable-hidden id="aws_s3" class="block my-4 space-y-4 <%= 'hidden' if value['service'] != 'aws_s3' %>">
|
||||
<%= render 'aws_form', f:, configs:, value: %>
|
||||
</disable-hidden>
|
||||
<disable-hidden id="google" class="block mt-4 space-y-4 mb-8 <%= 'hidden' if value['service'] != 'google' %>">
|
||||
<disable-hidden id="google" class="block mt-4 space-y-4 mb-6 <%= 'hidden' if value['service'] != 'google' %>">
|
||||
<%= render 'google_cloud_form', f:, configs:, value: %>
|
||||
</disable-hidden>
|
||||
<disable-hidden id="azure" class="block mt-4 space-y-4 mb-8 <%= 'hidden' if value['service'] != 'azure' %>">
|
||||
<disable-hidden id="azure" class="block mt-4 space-y-4 mb-6 <%= 'hidden' if value['service'] != 'azure' %>">
|
||||
<%= render 'azure_form', f:, configs:, value: %>
|
||||
</disable-hidden>
|
||||
<div class="form-control">
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
</div>
|
||||
<% elsif field['type'] == 'date' %>
|
||||
<div class="flex items-center px-0.5">
|
||||
<%= l(Date.parse(value)) %>
|
||||
<%= l(Date.parse(value), format: :long, locale: local_assigns[:locale]) %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="flex items-center px-0.5">
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<div style="max-width: 1600px" class="mx-auto pl-4">
|
||||
<div class="flex justify-between py-1.5 items-center pr-4">
|
||||
<div class="flex space-x-3">
|
||||
<a href="/"><%= render 'shared/logo' %></a>
|
||||
<a href="<%= template_path(@submission.template) %>" class="flex space-x-3">
|
||||
<span><%= render 'shared/logo' %></span>
|
||||
<span class="text-3xl font-semibold focus:text-clip"><%= @submission.template.name %></span>
|
||||
</div>
|
||||
</a>
|
||||
<div class="space-x-3 flex items-center">
|
||||
<% if last_submitter = @submission.submitters.select(&:completed_at?).max_by(&:completed_at) %>
|
||||
<download-button data-src="<%= submitter_download_index_path(last_submitter.slug) %>" class="base-button">
|
||||
@@ -45,7 +45,7 @@
|
||||
<% fields_index.dig(document.uuid, index)&.each do |(area, field)| %>
|
||||
<% value = values[field['uuid']] %>
|
||||
<% next if value.blank? %>
|
||||
<%= render 'submissions/value', area:, field:, attachments_index:, value: %>
|
||||
<%= render 'submissions/value', area:, field:, attachments_index:, value:, locale: current_account.locale %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
@@ -80,7 +80,7 @@
|
||||
</div>
|
||||
<% if submitter && !submitter.completed_at? %>
|
||||
<div class="mt-2 mb-1">
|
||||
<a class="btn btn-xs btn-primary w-full" target="_blank" href="<%= submit_form_url(slug: submitter.slug) %>">
|
||||
<a class="btn btn-sm btn-primary w-full" target="_blank" href="<%= submit_form_url(slug: submitter.slug) %>">
|
||||
Submit Form
|
||||
</a>
|
||||
</div>
|
||||
@@ -118,7 +118,7 @@
|
||||
<% elsif field['type'] == 'checkbox' %>
|
||||
<%= svg_icon('check', class: 'w-6 h-6') %>
|
||||
<% elsif field['type'] == 'date' %>
|
||||
<%= l(Date.parse(value)) %>
|
||||
<%= l(Date.parse(value), locale: current_account.locale, format: :long) %>
|
||||
<% else %>
|
||||
<%= Array.wrap(value).join(', ') %>
|
||||
<% end %>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<div class="flex items-center bg-base-300 rounded-xl p-4 mb-4">
|
||||
<div class="flex items-center">
|
||||
<div class="mr-3">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-10 h-10 text-gray-700 " width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="w-10 h-10" width="44" height="44" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
||||
<path d="M3 19c3.333 -2 5 -4 5 -6c0 -3 -1 -3 -2 -3s-2.032 1.085 -2 3c.034 2.048 1.658 2.877 2.5 4c1.5 2 2.5 2.5 3.5 1c.667 -1 1.167 -1.833 1.5 -2.5c1 2.333 2.333 3.5 4 3.5h2.5" />
|
||||
<path d="M20 17v-12c0 -1.121 -.879 -2 -2 -2s-2 .879 -2 2v12l2 2l2 -2z" />
|
||||
@@ -20,8 +20,8 @@
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<p class="text-lg text-gray-700 font-bold mb-1"><%= @submitter.submission.template.name %></p>
|
||||
<p class="text-sm text-gray-500">Signed on <%= l(@submitter.completed_at.to_date, format: :long) %></p>
|
||||
<p class="text-lg font-bold mb-1"><%= @submitter.submission.template.name %></p>
|
||||
<p class="text-sm">Signed on <%= l(@submitter.completed_at.to_date, format: :long, locale: @submitter.submission.template.account.locale) %></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<% fields_index = Templates.build_field_areas_index(@submitter.submission.template) %>
|
||||
<% values = @submitter.submission.submitters.reduce({}) { |acc, sub| acc.merge(sub.values) } %>
|
||||
<% values = @submitter.submission.submitters.where.not(id: @submitter.id).reduce({}) { |acc, sub| acc.merge(sub.values) } %>
|
||||
<% attachments_index = ActiveStorage::Attachment.where(record: @submitter.submission.submitters, name: :attachments).preload(:blob).index_by(&:uuid) %>
|
||||
<div class="mx-auto block pb-72" style="max-width: 1000px">
|
||||
<div class="mt-4 flex">
|
||||
@@ -17,7 +17,7 @@
|
||||
<% fields_index.dig(document.uuid, index)&.each do |(area, field)| %>
|
||||
<% value = values[field['uuid']] %>
|
||||
<% next if value.blank? %>
|
||||
<%= render 'submissions/value', area:, field:, attachments_index:, value: %>
|
||||
<%= render 'submissions/value', area:, field:, attachments_index:, value:, locale: @submitter.submission.template.account.locale %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
@@ -28,7 +28,7 @@
|
||||
<div class="fixed bottom-0 w-full h-0 z-20">
|
||||
<div class="mx-auto" style="max-width: 1000px">
|
||||
<div class="relative md:mx-32">
|
||||
<div class="shadow-md bg-base-100 absolute bottom-0 md:bottom-4 w-full border border-base-200 p-4 rounded">
|
||||
<div class="shadow-md bg-base-100 absolute bottom-0 md:bottom-4 w-full border border-base-200 border p-4 rounded">
|
||||
<submission-form data-submitter-uuid="<%= @submitter.uuid %>" data-submitter-slug="<%= @submitter.slug %>" data-attachments="<%= attachments_index.values.select { |e| e.record_id == @submitter.id }.to_json(only: %i[uuid], methods: %i[url filename content_type]) %>" data-fields="<%= @submitter.submission.template.fields.select { |f| f['submitter_uuid'] == @submitter.uuid }.to_json %>" data-values="<%= @submitter.values.to_json %>" data-authenticity-token="<%= form_authenticity_token %>"></submission-form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -16,18 +16,22 @@
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between mb-4 items-end">
|
||||
<p class="text-3xl font-bold">Submissions</p>
|
||||
<div class="flex space-x-2">
|
||||
<% if @template.submitters.to_a.size == 1 %>
|
||||
<%= render 'shared/clipboard_copy', text: start_form_url(slug: @template.slug), class: 'base-button', icon_class: 'w-6 h-6 text-white', copy_title: 'Copy Share Link', copied_title: 'Copied to Clipboard' %>
|
||||
<% end %>
|
||||
<%= link_to new_template_submission_path(@template), class: 'btn btn-primary text-base', data: { turbo_frame: 'modal' } do %>
|
||||
<%= svg_icon('plus', class: 'w-6 h-6 stroke-2') %>
|
||||
<span class="hidden md:block">Add Recipients</span>
|
||||
<% end %>
|
||||
<% if !@pagy.count.zero? || @template.submitters.to_a.size == 1 %>
|
||||
<div class="flex justify-between mb-4 items-end">
|
||||
<p class="text-3xl font-bold">Submissions</p>
|
||||
<div class="flex space-x-2">
|
||||
<% if @template.submitters.to_a.size == 1 %>
|
||||
<%= render 'shared/clipboard_copy', text: start_form_url(slug: @template.slug), class: 'base-button', icon_class: 'w-6 h-6 text-white', copy_title: 'Copy Share Link', copied_title: 'Copied to Clipboard' %>
|
||||
<% end %>
|
||||
<% unless @pagy.count.zero? %>
|
||||
<%= link_to new_template_submission_path(@template), class: 'btn btn-primary text-base', data: { turbo_frame: 'modal' } do %>
|
||||
<%= svg_icon('plus', class: 'w-6 h-6 stroke-2') %>
|
||||
<span class="hidden md:block">Add Recipients</span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<% status_badges = { 'awaiting' => 'badge-info', 'sent' => 'badge-info', 'completed' => 'badge-success', 'opened' => 'badge-warning' } %>
|
||||
<% if @submissions.present? %>
|
||||
<div class="space-y-4">
|
||||
@@ -46,9 +50,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex space-x-2 items-center">
|
||||
<span class="badge <%= status_badges[submitter.status] %> w-32 badge-lg btn-sm uppercase text-sm font-medium border-1">
|
||||
<%= submitter.status %>
|
||||
</span>
|
||||
<div class="tooltip flex" data-tip="<%= l(submitter.status_event_at.in_time_zone(current_account.timezone), format: :short, locale: current_account.locale) %>">
|
||||
<span class="badge <%= status_badges[submitter.status] %> w-32 badge-lg btn-sm uppercase text-sm font-medium border-1">
|
||||
<%= submitter.status %>
|
||||
</span>
|
||||
</div>
|
||||
<% if submitter.completed_at? %>
|
||||
<form onsubmit="event.preventDefault()">
|
||||
<button onclick="event.stopPropagation()">
|
||||
@@ -65,7 +71,7 @@
|
||||
</button>
|
||||
</form>
|
||||
<% else %>
|
||||
<%= render 'shared/clipboard_copy', text: submit_form_url(slug: submission.submitters.first.slug), class: 'btn btn-sm btn-neutral text-white w-36', icon_class: 'w-6 h-6 text-white', copy_title: 'Copy Link' %>
|
||||
<%= render 'shared/clipboard_copy', text: submit_form_url(slug: submission.submitters.first.slug), class: 'btn btn-sm btn-neutral text-white w-36 flex', icon_class: 'w-6 h-6 text-white', copy_title: 'Copy Link' %>
|
||||
<% end %>
|
||||
<%= button_to submitter.completed_at? ? 'Archive' : 'Remove', submission_path(submission), class: 'btn btn-outline btn-sm w-28', title: 'Delete', method: :delete, data: { turbo_confirm: 'Are you sure?' }, onclick: 'event.stopPropagation()' %>
|
||||
</div>
|
||||
@@ -82,10 +88,12 @@
|
||||
</span>
|
||||
<% unless submission.submitters.all?(&:completed_at?) %>
|
||||
<div class="flex items-center space-x-3">
|
||||
<span class="badge w-24 <%= status_badges[submitter.status] %> btn-xs uppercase text-xs font-medium border-1">
|
||||
<%= submitter.status %>
|
||||
</span>
|
||||
<%= render 'shared/clipboard_copy', text: submit_form_url(slug: submitter.slug), class: 'btn btn-xs text-xs btn-neutral text-white w-32', icon_class: 'w-4 h-4 text-white', copy_title: 'Copy Link' %>
|
||||
<div class="tooltip flex" data-tip="<%= l(submitter.status_event_at.in_time_zone(current_account.timezone), format: :short, locale: current_account.locale) %>">
|
||||
<span class="badge w-24 <%= status_badges[submitter.status] %> btn-xs uppercase text-xs font-medium border-1">
|
||||
<%= submitter.status %>
|
||||
</span>
|
||||
</div>
|
||||
<%= render 'shared/clipboard_copy', text: submit_form_url(slug: submitter.slug), class: 'btn btn-xs text-xs btn-neutral text-white w-32 flex', icon_class: 'w-4 h-4 text-white', copy_title: 'Copy Link' %>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
@@ -93,9 +101,11 @@
|
||||
</div>
|
||||
<div class="flex space-x-2 items-center">
|
||||
<% if submission.submitters.all?(&:completed_at?) %>
|
||||
<span class="badge <%= status_badges[submitter.status] %> w-32 badge-lg btn-sm uppercase text-sm font-medium border-1">
|
||||
<%= submitter.status %>
|
||||
</span>
|
||||
<div class="tooltip flex" data-tip="<%= l(submitter.status_event_at.in_time_zone(current_account.timezone), format: :short, locale: current_account.locale) %>">
|
||||
<span class="badge <%= status_badges[submitter.status] %> w-32 badge-lg btn-sm uppercase text-sm font-medium border-1">
|
||||
<%= submitter.status %>
|
||||
</span>
|
||||
</div>
|
||||
<form onsubmit="event.preventDefault()">
|
||||
<button onclick="event.stopPropagation()">
|
||||
<download-button data-src="<%= submitter_download_index_path(submission.submitters.select(&:completed_at?).max_by(&:completed_at).slug) %>" class="btn btn-sm btn-neutral text-white w-36">
|
||||
@@ -117,7 +127,18 @@
|
||||
</a>
|
||||
<% end %>
|
||||
</div>
|
||||
<%= render 'shared/pagination', pagy: @pagy, items_name: 'Submissions' %>
|
||||
<%= render 'shared/pagination', pagy: @pagy, items_name: 'submissions' %>
|
||||
<% else %>
|
||||
<%= render 'shared/no_data_banner' %>
|
||||
<div class="card bg-base-200">
|
||||
<div class="card-body text-center py-16">
|
||||
<div class="max-w-md mx-auto">
|
||||
<p class="text-3xl font-bold text-base-content mb-4">There are no Submissions yet</p>
|
||||
<p class="text-gray-600">Send an invitation to fill and submit the documents via email</p>
|
||||
<%= link_to new_template_submission_path(@template), class: 'base-button mt-6', data: { turbo_frame: 'modal' } do %>
|
||||
<%= svg_icon('plus', class: 'w-6 h-6 stroke-2') %>
|
||||
<span class="hidden md:block">Add Recipients</span>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<%= f.password_field :password, required: user.new_record?, class: 'base-input' %>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-control">
|
||||
<div class="form-control pt-2">
|
||||
<%= f.button button_title, class: 'base-button' %>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<%= user.last_sign_in_at ? l(user.last_sign_in_at, format: :short) : '-' %>
|
||||
<%= user.last_sign_in_at ? l(user.last_sign_in_at.in_time_zone(current_account.timezone), format: :short, locale: current_account.locale) : '-' %>
|
||||
</td>
|
||||
<td class="flex items-center space-x-2 justify-end">
|
||||
<%= link_to edit_user_path(user), class: 'btn btn-outline btn-xs', title: 'Edit', data: { turbo_frame: 'modal' } do %>
|
||||
@@ -58,6 +58,6 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<%= render 'shared/pagination', pagy: @pagy, items_name: 'Users' %>
|
||||
<%= render 'shared/pagination', pagy: @pagy, items_name: 'users' %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -20,6 +20,9 @@ module DocuSeal
|
||||
|
||||
config.active_storage.routes_prefix = ''
|
||||
|
||||
config.i18n.available_locales = %i[en en-US en-GB es-ES pt-PT de-DE]
|
||||
config.i18n.fallbacks = [:en]
|
||||
|
||||
config.action_view.frozen_string_literal = true
|
||||
|
||||
config.middleware.insert_before ActionDispatch::Static, Rack::Deflater
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ if ENV['RAILS_ENV'] == 'production' && ENV['SECRET_KEY_BASE'].to_s.empty?
|
||||
require 'dotenv'
|
||||
require 'securerandom'
|
||||
|
||||
dotenv_path = './docuseal.env'
|
||||
dotenv_path = "#{ENV.fetch('WORKDIR', '.')}/docuseal.env"
|
||||
|
||||
unless File.exist?(dotenv_path)
|
||||
default_env = <<~TEXT
|
||||
|
||||
@@ -56,6 +56,7 @@ Rails.application.routes.draw do
|
||||
resources :email, only: %i[index create], controller: 'email_settings'
|
||||
resources :esign, only: %i[index create], controller: 'esign_settings'
|
||||
resources :users, only: %i[index]
|
||||
resource :account, only: %i[show update]
|
||||
resources :profile, only: %i[index] do
|
||||
collection do
|
||||
patch :update_contact
|
||||
|
||||
@@ -4,6 +4,8 @@ class CreateAccounts < ActiveRecord::Migration[7.0]
|
||||
def change
|
||||
create_table :accounts do |t|
|
||||
t.string :name, null: false
|
||||
t.string :timezone, null: false
|
||||
t.string :locale, null: false
|
||||
|
||||
t.timestamps
|
||||
end
|
||||
|
||||
@@ -16,6 +16,8 @@ ActiveRecord::Schema[7.0].define(version: 2023_06_12_182744) do
|
||||
|
||||
create_table "accounts", force: :cascade do |t|
|
||||
t.string "name", null: false
|
||||
t.string "timezone", null: false
|
||||
t.string "locale", null: false
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
end
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
module Accounts
|
||||
module_function
|
||||
|
||||
def normalize_timezone(timezone)
|
||||
tzinfo = TZInfo::Timezone.get(ActiveSupport::TimeZone::MAPPING[timezone] || timezone)
|
||||
|
||||
::ActiveSupport::TimeZone.all.find { |e| e.tzinfo == tzinfo }&.name || timezone
|
||||
end
|
||||
end
|
||||
@@ -135,7 +135,7 @@ module Submissions
|
||||
height - (area['y'] * height))
|
||||
end
|
||||
else
|
||||
value = I18n.l(Date.parse(value)) if field['type'] == 'date'
|
||||
value = I18n.l(Date.parse(value), format: :long) if field['type'] == 'date'
|
||||
|
||||
text = HexaPDF::Layout::TextFragment.create(Array.wrap(value).join(', '), font: pdf.fonts.add(FONT_NAME),
|
||||
font_size: FONT_SIZE)
|
||||
|
||||
@@ -8,6 +8,6 @@ module.exports = {
|
||||
'./app/views/start_form/**/*.erb',
|
||||
'./app/views/shared/_button_title.html.erb',
|
||||
'./app/views/shared/_attribution.html.erb',
|
||||
'./app/views/send_submission_copy/**/*.erb'
|
||||
'./app/views/send_submission_email/**/*.erb'
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user