Merge branch 'dev'

This commit is contained in:
Alex
2023-12-09 15:44:25 +01:00
67 changed files with 4107 additions and 9445 deletions

2
.tool-versions Normal file
View File

@@ -0,0 +1,2 @@
erlang 26.1.2
elixir 1.15.7-otp-26

View File

@@ -1,3 +1,16 @@
## v1.7.0
- Add keyboard shortcuts to control settings (#64) (@Dhanus3133)
- Add embed (Youtube or any web content) as an interraction (#72) (@Dhanus3133)
- Add pinned messages (#62) (@haruncurak)
- Add reset password feature
- Add indication when a form is saved
- Add Postmark adapter
- Add the ability to send mail to facilitators invited to manage an event
- Allow navigation within presenter window (#63) (@railsmechanic)
- Change default avatar style
- Security updates
## v1.6.0
- Improve QR code readability
- Add ARM Docker image

View File

@@ -7,8 +7,8 @@ Don't forget to give the project a star! Thanks again!
2. Create your Feature Branch (`git checkout -b feature/amazing_feature`)
3. Commit your Changes (`git commit -m 'Add some amazing feature'`)
4. Push to the Branch (`git push origin feature/amazing_feature`)
5. Open a Pull Request
5. Open a Pull Request on `dev` branch
## Translations
You can contribute to the translations of this project by joining the POEditor project [here](https://poeditor.com/join/project/HbRyvyt3TT).
You can contribute to the translations by editing or addind PO files in `/priv/gettext/`

View File

@@ -99,7 +99,7 @@ RUN mkdir /home/nobody && chown nobody /home/nobody
WORKDIR "/app"
RUN mkdir /app/uploads
RUN chown nobody /app
RUN chown -R nobody /app
# Only copy the final release from the build stage
COPY --from=builder --chown=nobody:root /app/_build/prod/rel/claper ./

View File

@@ -99,7 +99,7 @@ RUN mkdir /home/nobody && chown nobody /home/nobody
WORKDIR "/app"
RUN mkdir /app/uploads
RUN chown nobody /app -R
RUN chown -R nobody /app -R
# Only copy the final release from the build stage
COPY --from=builder --chown=nobody:root /app/_build/prod/rel/claper ./

View File

@@ -113,9 +113,21 @@ A Docker Compose [reference file](https://github.com/ClaperCo/Claper/blob/main/d
```sh
git clone https://github.com/ClaperCo/Claper.git
cd Claper
docker-compose up
docker compose up
```
### Using Docker Compose for Dev
To easy check new features, it is possible to directly build the Docker image from the source code and run the container with the [docker-compose-dev.yml](https://github.com/ClaperCo/Claper/blob/main/docker-compose-dev.yml) file.
```sh
git clone https://github.com/ClaperCo/Claper.git
cd Claper
docker compose -f docker-compose-dev.yml up
```
<!-- CONTRIBUTING -->
## Contributing
@@ -139,7 +151,7 @@ Distributed under the GPLv3 License. See `LICENSE.txt` for more information.
<!-- CONTACT -->
## Contact
[![](https://img.shields.io/badge/@alxlion__-1DA1F2?style=for-the-badge&logo=twitter&logoColor=white)](https://twitter.com/alxlion_)
[![](https://img.shields.io/badge/@alxlion__-000000?style=for-the-badge&logo=x&logoColor=white)](https://x.com/alxlion_)
Project Link: [https://github.com/ClaperCo/Claper](https://github.com/ClaperCo/Claper)

View File

@@ -328,8 +328,6 @@ Hooks.QRCode = {
width: this.el.dataset.dynamic ? document.documentElement.clientWidth * .25 : 240,
height: this.el.dataset.dynamic ? document.documentElement.clientWidth * .25 : 240,
margin: 0,
image:
"/images/logo.png",
data: url,
cornersSquareOptions: {
type: "square"

View File

@@ -18,14 +18,14 @@ export class Manager {
document.getElementById("slide-preview-" + data.current_page).scrollIntoView({
block: 'center',
behavior: 'smooth'
});
});
}, data.timeout ? data.timeout : 0)
}
})
window.addEventListener('keydown', (e) => {
if (e.target.tagName.toLowerCase() != "input") {
if ((e.target.tagName || '').toLowerCase() != "input") {
e.preventDefault()
switch (e.key) {
@@ -41,7 +41,7 @@ export class Manager {
case 'ArrowDown':
this.nextPage()
break
}
}
}
});
}
@@ -54,25 +54,25 @@ export class Manager {
document.getElementById("slide-preview-" + this.currentPage).scrollIntoView({
block: 'center',
behavior: 'smooth'
});
});
}
}
nextPage() {
if(this.currentPage == this.maxPage - 1)
return;
this.currentPage += 1;
this.context.pushEventTo(this.context.el, "current-page", {"page": this.currentPage.toString()});
}
prevPage() {
if(this.currentPage == 0)
if (this.currentPage == this.maxPage - 1)
return;
this.currentPage += 1;
this.context.pushEventTo(this.context.el, "current-page", { "page": this.currentPage.toString() });
}
prevPage() {
if (this.currentPage == 0)
return;
this.currentPage -= 1;
this.context.pushEventTo(this.context.el, "current-page", {"page": this.currentPage.toString()});
this.context.pushEventTo(this.context.el, "current-page", { "page": this.currentPage.toString() });
}
}
}

View File

@@ -18,11 +18,11 @@ export class Presenter {
slideBy: 'page',
center: true,
autoplay: false,
controls: false,
controls: false,
swipeAngle: false,
startIndex: this.currentPage,
loop: false,
nav: false
nav: false
});
this.context.handleEvent('page', data => {
@@ -35,12 +35,19 @@ export class Presenter {
if (data.value) {
document.getElementById("post-list").classList.remove("animate__animated", "animate__fadeOutLeft")
document.getElementById("post-list").classList.add("animate__animated", "animate__fadeInLeft")
document.getElementById("pinned-post-list").classList.remove("animate__animated", "animate__fadeOutLeft")
document.getElementById("pinned-post-list").classList.add("animate__animated", "animate__fadeInLeft")
} else {
document.getElementById("post-list").classList.remove("animate__animated", "animate__fadeInLeft")
document.getElementById("post-list").classList.add("animate__animated", "animate__fadeOutLeft")
document.getElementById("pinned-post-list").classList.remove("animate__animated", "animate__fadeInLeft")
document.getElementById("pinned-post-list").classList.add("animate__animated", "animate__fadeOutLeft")
}
})
this.context.handleEvent('poll-visible', data => {
if (data.value) {
document.getElementById("poll").classList.remove("animate__animated", "animate__fadeOut")
@@ -69,37 +76,49 @@ export class Presenter {
case 'f': // F
this.fullscreen()
break
}
case 'ArrowUp':
window.opener.dispatchEvent(new KeyboardEvent('keydown', { 'key': 'ArrowUp' }));
break
case 'ArrowLeft':
window.opener.dispatchEvent(new KeyboardEvent('keydown', { 'key': 'ArrowLeft' }));
break
case 'ArrowRight':
window.opener.dispatchEvent(new KeyboardEvent('keydown', { 'key': 'ArrowRight' }));
break
case 'ArrowDown':
window.opener.dispatchEvent(new KeyboardEvent('keydown', { 'key': 'ArrowDown' }));
break
}
}
});
}
fullscreen() {
var docEl = document.getElementById("presenter")
var docEl = document.getElementById("presenter")
try {
docEl.webkitRequestFullscreen()
.then(function() {
try {
docEl.webkitRequestFullscreen()
.then(function () {
})
.catch(function(error) {
.catch(function (error) {
});
} catch (e) {
docEl.requestFullscreen()
.then(function() {
} catch (e) {
docEl.requestFullscreen()
.then(function () {
})
.catch(function(error) {
.catch(function (error) {
});
docEl.mozRequestFullScreen()
.then(function() {
docEl.mozRequestFullScreen()
.then(function () {
})
.catch(function(error) {
.catch(function (error) {
});
}
}
}
}
}

6997
assets/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,13 +3,12 @@
"deploy": "NODE_ENV=production tailwindcss --postcss --minify --input=css/app.css --output=../priv/static/assets/app.css"
},
"devDependencies": {
"alpinejs": "^3.4.2",
"autoprefixer": "^10.3.7",
"cpx": "^1.5.0",
"esbuild": "^0.14.14",
"flatpickr": "^4.6.9",
"postcss": "^8.3.9",
"postcss-import": "^14.0.2",
"alpinejs": "^3.13.1",
"autoprefixer": "^10.4.15",
"esbuild": "^0.14.54",
"flatpickr": "^4.6.13",
"postcss": "^8.4.29",
"postcss-import": "^15.1.0",
"tailwindcss": "^3.3.3"
},
"dependencies": {

View File

@@ -80,27 +80,25 @@ const colors = {
module.exports = {
mode: 'jit',
purge: {
content: [
'./js/**/*.js',
'../lib/*_web/**/*.*ex'
],
safelist: [
'-top-1.5',
'top-1',
'left-3',
'top-6',
'h-5',
'left-2.5',
'top-3',
'h-7',
'bg-secondary-600',
'text-white',
'bg-white',
'text-gray-600'
]
},
darkMode: false, // or 'media' or 'class'
content: [
'./js/**/*.js',
'../lib/*_web/**/*.*ex'
],
safelist: [
'-top-1.5',
'top-1',
'left-3',
'top-6',
'h-5',
'left-2.5',
'top-3',
'h-7',
'bg-secondary-600',
'text-white',
'bg-white',
'text-gray-600'
],
darkMode: 'media',
theme: {
extend: {
backgroundSize: {

File diff suppressed because it is too large Load Diff

View File

@@ -20,18 +20,6 @@ config :claper, ClaperWeb.Gettext,
default_locale: "en",
locales: ~w(fr en de)
# Configures the mailer
#
# By default it uses the "Local" adapter which stores the emails
# locally. You can see the emails in your browser, at "/dev/mailbox".
#
# For production it's recommended to configure a different adapter
# at the `config/runtime.exs`.
config :claper, Claper.Mailer, adapter: Swoosh.Adapters.Local
# Swoosh API client is needed for adapters other than SMTP.
config :swoosh, :api_client, false
config :dart_sass,
version: "1.58.0",
default: [

View File

@@ -110,18 +110,32 @@ config :claper, ClaperWeb.MailboxGuard,
get_var_from_path_or_env(config_dir, "ENABLE_MAILBOX_ROUTE", "false")
|> String.to_existing_atom()
if mail_transport == "smtp" do
config :claper, Claper.Mailer,
adapter: Swoosh.Adapters.SMTP,
relay: smtp_relay,
username: smtp_username,
password: smtp_password,
ssl: smtp_ssl,
# always, never, if_available
tls: smtp_tls,
# always, never, if_available
auth: smtp_auth,
port: smtp_port
case mail_transport do
"smtp" ->
config :claper, Claper.Mailer,
adapter: Swoosh.Adapters.SMTP,
relay: smtp_relay,
username: smtp_username,
password: smtp_password,
ssl: smtp_ssl,
# always, never, if_available
tls: smtp_tls,
# always, never, if_available
auth: smtp_auth,
port: smtp_port
config :swoosh, :api_client, false
"postmark" ->
config :claper, Claper.Mailer,
adapter: Swoosh.Adapters.Postmark,
api_key: get_var_from_path_or_env(config_dir, "POSTMARK_API_KEY", nil)
config :swoosh, :api_client, Swoosh.ApiClient.Hackney
_ ->
config :claper, Claper.Mailer, adapter: Swoosh.Adapters.Local
config :swoosh, :api_client, false
end
config :ex_aws,

38
docker-compose-dev.yml Normal file
View File

@@ -0,0 +1,38 @@
version: "3.0"
services:
db:
image: postgres:9
ports:
- 5432:5432
volumes:
- postgres-data:/var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: claper
POSTGRES_USER: claper
POSTGRES_DB: claper
healthcheck:
test: ["CMD-SHELL", "pg_isready -U claper"]
interval: 5s
timeout: 5s
retries: 10
app:
build: .
user: 0:0
ports:
- 4000:4000
volumes:
- uploads:/app/uploads
environment:
DATABASE_URL: postgres://claper:claper@db:5432/claper
SECRET_KEY_BASE: 0LZiQBLw4WvqPlz4cz8RsHJlxNiSqM9B48y4ChyJ5v1oA0L/TPIqRjQNdPZN3iEG
MAIL_TRANSPORT: local
ENDPOINT_PORT: 4000
PRESENTATION_STORAGE: local
MAX_FILE_SIZE_MB: 15
ENABLE_ACCOUNT_CREATION: true
depends_on:
db:
condition: service_healthy
volumes:
postgres-data:
uploads:

View File

@@ -10,8 +10,14 @@ services:
POSTGRES_PASSWORD: claper
POSTGRES_USER: claper
POSTGRES_DB: claper
healthcheck:
test: ["CMD-SHELL", "pg_isready -U claper"]
interval: 5s
timeout: 5s
retries: 10
app:
image: ghcr.io/claperco/claper:latest
user: 0:0
ports:
- 4000:4000
volumes:
@@ -25,6 +31,7 @@ services:
MAX_FILE_SIZE_MB: 15
ENABLE_ACCOUNT_CREATION: true
depends_on:
- db
db:
condition: service_healthy
volumes:
uploads:

View File

@@ -19,7 +19,7 @@ AWS_REGION | - | - | _only for s3_ | The region where the bucket is located
Variable | Values | Default | Required | Description
--- | --- | --- | --- | ---
MAIL_TRANSPORT | local, smtp | local | - | Define how the emails will be sent
MAIL_TRANSPORT | local, smtp, postmark | local | - | Define how the emails will be sent
MAIL_FROM | - | Claper | - | Email address used to send emails
MAIL_FROM_NAME | - | noreply@claper.co | - | Name used to send emails
SMTP_RELAY | - | - | _only for smtp_ | SMTP relay server
@@ -32,6 +32,7 @@ SMTP_SSL | true, false | true | - | SMTP SSL
ENABLE_MAILBOX_ROUTE | true, false | false | - | Enable/disable route to local mailbox (`/dev/mailbox`)
MAILBOX_USER | - | - | - | Basic auth user for mailbox route
MAILBOX_PASSWORD | - | - | - | Basic auth password for mailbox route
POSTMARK_API_KEY | - | - | _only for postmark_ | Postmark API key
### Application

View File

@@ -53,9 +53,20 @@ A Docker Compose [reference file](https://github.com/ClaperCo/Claper/blob/main/d
```sh
git clone https://github.com/ClaperCo/Claper.git
cd Claper
docker-compose up
docker compose up
```
## Using Docker Compose for Dev
To easy check new features, it is possible to directly build the Docker image from the source code and run the container with the [docker-compose-dev.yml](https://github.com/ClaperCo/Claper/blob/main/docker-compose-dev.yml) file.
```sh
git clone https://github.com/ClaperCo/Claper.git
cd Claper
docker compose -f docker-compose-dev.yml up
```
### ARM architecture
If you are using an ARM architecture (like Apple M1), the original Docker image won't work. You can build the image yourself by replacing the `BUILDER_IMAGE` argument in the `Dockerfile` with `ARG BUILDER_IMAGE="hexpm/elixir-arm64:1.13.2-erlang-24.2.1-debian-bullseye-20210902-slim"` and then build the image as described above.

View File

@@ -12,6 +12,8 @@ Users can send instant message during the presentation and interact to others me
You can choose to be anoynmous or use your own name before sending a message.
You can also pin a message to the screen to highlight it and only show pinned messages.
## Polls
You can add polls during your presentation. Users can vote to the poll and see the results in real time.
@@ -32,6 +34,14 @@ When you create a new presentation, click on **Present/Customize**, select the s
After your presentation, you can export all the submissions in CSV format.
## Web content
Any web content like Youtube, Slideshare, Google Slides, etc. can be embedded in your presentation.
When you create a new presentation, click on **Present/Customize**, select the slide where you want to add embed and click **Add interaction**.
You can choose to show the embed in the attendee side, so your audience can see the embed content during your presentation.
## Moderation tools
You can moderate the messages during your presentation. You can delete messages or ban users from the dashboard.

View File

@@ -0,0 +1,11 @@
defmodule Claper.Accounts.LeaderNotifier do
alias Claper.Mailer
def deliver_event_invitation(event_name, email, url) do
e = ClaperWeb.Notifiers.LeaderNotifier.event_invitation(event_name, email, url)
with {:ok, _metadata} <- Mailer.deliver(e) do
{:ok, email}
end
end
end

View File

@@ -73,7 +73,7 @@ defmodule Claper.Accounts.User do
def password_changeset(user, attrs, opts \\ []) do
user
|> cast(attrs, [:password])
|> validate_confirmation(:password, message: "does not match password")
|> validate_confirmation(:password)
|> validate_password(opts)
end

View File

@@ -5,10 +5,13 @@ defmodule Claper.Accounts.UserNotifier do
# Delivers the email using the application mailer.
defp deliver(recipient, subject, body) do
from_name = Application.get_env(:claper, :mail)[:from_name]
from_email = Application.get_env(:claper, :mail)[:from]
email =
new()
|> to(recipient)
|> from({"MyApp", "contact@example.com"})
|> from({from_name, from_email})
|> subject(subject)
|> text_body(body)

189
lib/claper/embeds.ex Normal file
View File

@@ -0,0 +1,189 @@
defmodule Claper.Embeds do
@moduledoc """
The Embeds context.
"""
import Ecto.Query, warn: false
alias Claper.Repo
alias Claper.Embeds.Embed
@doc """
Returns the list of embeds for a given presentation file.
## Examples
iex> list_embeds(123)
[%Embed{}, ...]
"""
def list_embeds(presentation_file_id) do
from(e in Embed,
where: e.presentation_file_id == ^presentation_file_id,
order_by: [asc: e.id, asc: e.position]
)
|> Repo.all()
end
@doc """
Returns the list of embeds for a given presentation file and a given position.
## Examples
iex> list_embeds_at_position(123, 0)
[%Embed{}, ...]
"""
def list_embeds_at_position(presentation_file_id, position) do
from(e in Embed,
where: e.presentation_file_id == ^presentation_file_id and e.position == ^position,
order_by: [asc: e.id]
)
|> Repo.all()
end
@doc """
Gets a single embed.
Raises `Ecto.NoResultsError` if the Embed does not exist.
## Examples
iex> get_embed!(123)
%Embed{}
iex> get_embed!(456)
** (Ecto.NoResultsError)
"""
def get_embed!(id, preload \\ []),
do: Repo.get!(Embed, id) |> Repo.preload(preload)
@doc """
Gets a single embed for a given position.
## Examples
iex> get_embed_current_position(123, 0)
%Embed{}
"""
def get_embed_current_position(presentation_file_id, position) do
from(e in Embed,
where:
e.position == ^position and e.presentation_file_id == ^presentation_file_id and
e.enabled == true
)
|> Repo.one()
end
@doc """
Creates a embed.
## Examples
iex> create_embed(%{field: value})
{:ok, %Embed{}}
iex> create_embed(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_embed(attrs \\ %{}) do
%Embed{}
|> Embed.changeset(attrs)
|> Repo.insert()
end
@doc """
Updates a embed.
## Examples
iex> update_embed("123e4567-e89b-12d3-a456-426614174000", embed, %{field: new_value})
{:ok, %Embed{}}
iex> update_embed("123e4567-e89b-12d3-a456-426614174000", embed, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_embed(event_uuid, %Embed{} = embed, attrs) do
embed
|> Embed.changeset(attrs)
|> Repo.update()
|> case do
{:ok, embed} ->
broadcast({:ok, embed, event_uuid}, :embed_updated)
{:error, changeset} ->
{:error, %{changeset | action: :update}}
end
end
@doc """
Deletes a embed.
## Examples
iex> delete_embed("123e4567-e89b-12d3-a456-426614174000", embed)
{:ok, %Embed{}}
iex> delete_embed("123e4567-e89b-12d3-a456-426614174000", embed)
{:error, %Ecto.Changeset{}}
"""
def delete_embed(event_uuid, %Embed{} = embed) do
{:ok, embed} = Repo.delete(embed)
broadcast({:ok, embed, event_uuid}, :embed_deleted)
end
@doc """
Returns an `%Ecto.Changeset{}` for tracking embed changes.
## Examples
iex> change_embed(embed)
%Ecto.Changeset{data: %Embed{}}
"""
def change_embed(%Embed{} = embed, attrs \\ %{}) do
Embed.changeset(embed, attrs)
end
def disable_all(presentation_file_id, position) do
from(e in Embed,
where: e.presentation_file_id == ^presentation_file_id and e.position == ^position
)
|> Repo.update_all(set: [enabled: false])
end
def set_status(id, presentation_file_id, position, status) do
if status do
from(e in Embed,
where:
e.presentation_file_id == ^presentation_file_id and e.position == ^position and
e.id != ^id
)
|> Repo.update_all(set: [enabled: false])
end
from(e in Embed,
where:
e.presentation_file_id == ^presentation_file_id and e.position == ^position and
e.id == ^id
)
|> Repo.update_all(set: [enabled: status])
end
defp broadcast({:error, _reason} = error, _embed), do: error
defp broadcast({:ok, embed, event_uuid}, event) do
Phoenix.PubSub.broadcast(
Claper.PubSub,
"event:#{event_uuid}",
{event, embed}
)
{:ok, embed}
end
end

View File

@@ -0,0 +1,41 @@
defmodule Claper.Embeds.Embed do
use Ecto.Schema
import Ecto.Changeset
import ClaperWeb.Gettext
@derive {Jason.Encoder, only: [:title, :content, :position, :attendee_visibility]}
schema "embeds" do
field :title, :string
field :content, :string
field :enabled, :boolean, default: true
field :position, :integer, default: 0
field :attendee_visibility, :boolean, default: false
belongs_to :presentation_file, Claper.Presentations.PresentationFile
timestamps()
end
@doc false
def changeset(embed, attrs \\ %{}) do
embed
|> cast(attrs, [
:enabled,
:title,
:content,
:presentation_file_id,
:position,
:attendee_visibility
])
|> validate_required([
:title,
:content,
:presentation_file_id,
:position,
:attendee_visibility
])
|> validate_format(:content, ~r/<iframe.*<\/iframe>/,
message: gettext("Invalid embed format (should start with <iframe> and end with </iframe>)")
)
end
end

View File

@@ -275,11 +275,12 @@ defmodule Claper.Events do
|> Ecto.Multi.run(:from_event, fn _repo, _changes ->
{:ok,
get_user_event!(user_id, from_event_uuid,
presentation_file: [polls: [:poll_opts], forms: []]
presentation_file: [polls: [:poll_opts], forms: [], embeds: []]
)}
end)
|> Ecto.Multi.run(:to_event, fn _repo, _changes ->
{:ok, get_user_event!(user_id, to_event_uuid, presentation_file: [:polls, :forms])}
{:ok,
get_user_event!(user_id, to_event_uuid, presentation_file: [:polls, :forms, :embeds])}
end)
|> Ecto.Multi.run(:polls, fn _repo, %{from_event: from_event, to_event: to_event} ->
{:ok,
@@ -321,6 +322,22 @@ defmodule Claper.Events do
end
end)}
end)
|> Ecto.Multi.run(:embeds, fn _repo, %{from_event: from_event, to_event: to_event} ->
{:ok,
from_event.presentation_file.embeds
|> Enum.each(fn embed ->
if embed.position < to_event.presentation_file.length do
Claper.Embeds.create_embed(%{
title: embed.title,
content: embed.content,
position: embed.position,
enabled: embed.enabled,
attendee_visibility: embed.attendee_visibility,
presentation_file_id: to_event.presentation_file.id
})
end
end)}
end)
|> Repo.transaction() do
{:ok, %{to_event: to_event}} -> {:ok, to_event}
end

View File

@@ -181,20 +181,22 @@ defmodule Claper.Forms do
|> Repo.update_all(set: [enabled: false])
end
def set_default(id, presentation_file_id, position) do
from(f in Form,
where:
f.presentation_file_id == ^presentation_file_id and f.position == ^position and
f.id != ^id
)
|> Repo.update_all(set: [enabled: false])
def set_status(id, presentation_file_id, position, status) do
if status do
from(f in Form,
where:
f.presentation_file_id == ^presentation_file_id and f.position == ^position and
f.id != ^id
)
|> Repo.update_all(set: [enabled: false])
end
from(f in Form,
where:
f.presentation_file_id == ^presentation_file_id and f.position == ^position and
f.id == ^id
)
|> Repo.update_all(set: [enabled: true])
|> Repo.update_all(set: [enabled: status])
end
defp broadcast({:error, _reason} = error, _form), do: error

View File

@@ -275,20 +275,22 @@ defmodule Claper.Polls do
|> Repo.update_all(set: [enabled: false])
end
def set_default(id, presentation_file_id, position) do
from(p in Poll,
where:
p.presentation_file_id == ^presentation_file_id and p.position == ^position and
p.id != ^id
)
|> Repo.update_all(set: [enabled: false])
def set_status(id, presentation_file_id, position, status) do
if status do
from(p in Poll,
where:
p.presentation_file_id == ^presentation_file_id and p.position == ^position and
p.id != ^id
)
|> Repo.update_all(set: [enabled: false])
end
from(p in Poll,
where:
p.presentation_file_id == ^presentation_file_id and p.position == ^position and
p.id == ^id
)
|> Repo.update_all(set: [enabled: true])
|> Repo.update_all(set: [enabled: status])
end
defp broadcast({:error, _reason} = error, _poll), do: error

View File

@@ -24,6 +24,38 @@ defmodule Claper.Posts do
|> Repo.preload(preload)
end
@doc """
Get only the pinned event posts.
"""
def list_pinned_posts(event_id, preload \\ []) do
from(p in Post,
join: e in Claper.Events.Event,
on: p.event_id == e.id,
select: p,
# Only pinned posts
where: e.uuid == ^event_id and p.pinned == true,
order_by: [asc: p.id]
)
|> Repo.all()
|> Repo.preload(preload)
end
@doc """
Get only the unpinned event posts.
"""
def list_unpinned_posts(event_id, preload \\ []) do
from(p in Post,
join: e in Claper.Events.Event,
on: p.event_id == e.id,
select: p,
# Only unpinned posts
where: e.uuid == ^event_id and p.pinned == false,
order_by: [asc: p.id]
)
|> Repo.all()
|> Repo.preload(preload)
end
def reacted_posts(event_id, user_id, icon) when is_number(user_id) do
from(reaction in Claper.Posts.Reaction,
join: post in Claper.Posts.Post,
@@ -99,10 +131,41 @@ defmodule Claper.Posts do
"""
def update_post(%Post{} = post, attrs) do
post
|> Post.changeset(attrs)
|> Repo.update()
|> broadcast(:post_updated)
changeset = Post.changeset(post, attrs)
result = changeset |> Repo.update()
result |> broadcast(:post_updated)
end
@doc """
Pins or unpins a post based on its current state.
## Examples
iex> toggle_pin_post(post)
{:ok, %Post{}}
iex> toggle_pin_post(invalid_post)
{:error, %Ecto.Changeset{}}
"""
def toggle_pin_post(%Post{} = post) do
# Toggling the pinned state
new_pinned_state = not post.pinned
changeset = Post.changeset(post, %{pinned: new_pinned_state})
result = changeset |> Repo.update()
# Broadcast the appropriate message based on the new state
broadcast_message =
if new_pinned_state do
:post_pinned
else
:post_unpinned
end
result |> broadcast(broadcast_message)
end
@doc """

View File

@@ -11,6 +11,7 @@ defmodule Claper.Posts.Post do
field :name, :string
field :attendee_identifier, :string
field :position, :integer, default: 0
field :pinned, :boolean, default: false
belongs_to :event, Claper.Events.Event
belongs_to :user, Claper.Accounts.User
@@ -30,7 +31,8 @@ defmodule Claper.Posts.Post do
:love_count,
:lol_count,
:name,
:position
:position,
:pinned
])
|> validate_required([:body, :position])
|> validate_length(:body, min: 2, max: 255)

View File

@@ -10,6 +10,7 @@ defmodule Claper.Presentations.PresentationFile do
belongs_to :event, Claper.Events.Event
has_many :polls, Claper.Polls.Poll
has_many :forms, Claper.Forms.Form
has_many :embeds, Claper.Embeds.Embed
has_one :presentation_state, Claper.Presentations.PresentationState, on_replace: :delete
timestamps()

View File

@@ -10,6 +10,7 @@ defmodule Claper.Presentations.PresentationState do
field :chat_enabled, :boolean
field :anonymous_chat_enabled, :boolean
field :banned, {:array, :string}, default: []
field :show_only_pinned, :boolean, default: false
belongs_to :presentation_file, Claper.Presentations.PresentationFile
@@ -27,7 +28,8 @@ defmodule Claper.Presentations.PresentationState do
:banned,
:presentation_file_id,
:chat_enabled,
:anonymous_chat_enabled
:anonymous_chat_enabled,
:show_only_pinned
])
|> validate_required([])
end

View File

@@ -1,13 +1,14 @@
defmodule ClaperWeb.UserResetPasswordController do
use ClaperWeb, :controller
import Phoenix.LiveView.Controller
alias Claper.Accounts
alias Claper.Accounts.User
plug(:get_user_by_reset_password_token when action in [:edit])
def new(conn, _params) do
render(conn, "new.html")
changeset = Accounts.change_user_registration(%User{})
render(conn, "new.html", changeset: changeset)
end
def create(conn, %{"user" => %{"email" => email}}) do
@@ -22,13 +23,30 @@ defmodule ClaperWeb.UserResetPasswordController do
conn
|> put_flash(
:info,
"If your email is in our system, you'll receive instructions to reset your password shortly."
gettext(
"If your email is in our system, you'll receive instructions to reset your password shortly."
)
)
|> redirect(to: "/")
end
def edit(conn, _params) do
live_render(conn, ClaperWeb.UserLive.ResetPassword)
def edit(conn, %{"token" => token}) do
changeset = Accounts.change_user_password(%User{})
render(conn, "edit.html", changeset: changeset, token: token)
end
def update(conn, %{"user" => user_params, "token" => token}) do
user = Accounts.get_user!(get_session(conn, "user_id"))
case Accounts.reset_user_password(user, user_params) do
{:ok, _user} ->
conn
|> put_flash(:info, gettext("Password updated successfully."))
|> redirect(to: "/")
{:error, changeset} ->
render(conn, "edit.html", changeset: changeset, token: token)
end
end
defp get_user_by_reset_password_token(conn, _opts) do
@@ -38,7 +56,7 @@ defmodule ClaperWeb.UserResetPasswordController do
put_session(conn, "user_id", user.id)
else
conn
|> put_flash(:error, "Reset password link is invalid or it has expired.")
|> put_flash(:error, gettext("Reset password link is invalid or it has expired."))
|> redirect(to: "/")
|> halt()
end

View File

@@ -0,0 +1,92 @@
defmodule ClaperWeb.EmbedLive.FormComponent do
use ClaperWeb, :live_component
alias Claper.Embeds
@impl true
def update(%{embed: embed} = assigns, socket) do
changeset = Embeds.change_embed(embed)
{:ok,
socket
|> assign(assigns)
|> assign_new(:dark, fn -> false end)
|> assign(:embeds, list_embeds(assigns))
|> assign(:changeset, changeset)}
end
@impl true
def handle_event("delete", %{"id" => id}, socket) do
embed = Embeds.get_embed!(id)
{:ok, _} = Embeds.delete_embed(socket.assigns.event_uuid, embed)
{:noreply, socket |> push_redirect(to: socket.assigns.return_to)}
end
@impl true
def handle_event("validate", %{"embed" => embed_params}, socket) do
changeset =
socket.assigns.embed
|> Embeds.change_embed(embed_params)
|> Map.put(:action, :validate)
{:noreply, socket |> assign(:changeset, changeset)}
end
@impl true
def handle_event("save", %{"embed" => embed_params}, socket) do
save_embed(socket, socket.assigns.live_action, embed_params)
end
defp save_embed(socket, :edit, embed_params) do
case Embeds.update_embed(
socket.assigns.event_uuid,
socket.assigns.embed,
embed_params
) do
{:ok, _embed} ->
{:noreply,
socket
|> push_redirect(to: socket.assigns.return_to)}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign(socket, :changeset, changeset)}
end
end
defp save_embed(socket, :new, embed_params) do
case Embeds.create_embed(
embed_params
|> Map.put("presentation_file_id", socket.assigns.presentation_file.id)
|> Map.put("position", socket.assigns.position)
|> Map.put("enabled", false)
) do
{:ok, embed} ->
{:noreply,
socket
|> maybe_change_current_embed(embed)
|> push_redirect(to: socket.assigns.return_to)}
{:error, %Ecto.Changeset{} = changeset} ->
{:noreply, assign(socket, changeset: changeset)}
end
end
defp maybe_change_current_embed(socket, %{enabled: true} = embed) do
embed = Embeds.get_embed!(embed.id)
Phoenix.PubSub.broadcast(
Claper.PubSub,
"event:#{socket.assigns.event_uuid}",
{:current_embed, embed}
)
socket
end
defp maybe_change_current_embed(socket, _), do: socket
defp list_embeds(assigns) do
Embeds.list_embeds(assigns.presentation_file.id)
end
end

View File

@@ -0,0 +1,70 @@
<div>
<.form
:let={f}
for={@changeset}
id="embed-form"
phx-target={@myself}
phx-change="validate"
phx-submit="save"
>
<div class="my-3 mb-10">
<ClaperWeb.Component.Input.text
form={f}
key={:title}
name={gettext("Title")}
labelClass={if @dark, do: "text-white"}
fieldClass={if @dark, do: "bg-gray-700 text-white"}
autofocus="true"
required="true"
/>
<div class="mt-3">
<ClaperWeb.Component.Input.textarea
form={f}
key={:content}
name={gettext("The iframe component")}
labelClass={if @dark, do: "text-white"}
fieldClass={if @dark, do: "bg-gray-700 text-white"}
autofocus="true"
required="true"
/>
</div>
<div class="flex gap-x-2 mb-5 mt-3">
<%= checkbox(f, :attendee_visibility, class: "h-4 w-5") %>
<%= label(
f,
:attendee_visibility,
gettext("Attendee can view the web content on their device"),
class: "text-sm font-medium"
) %>
</div>
</div>
<div class="flex space-x-3">
<button
type="submit"
phx_disable_with="Loading..."
class="w-full lg:w-auto px-6 text-white py-2 rounded-md tracking-wide font-bold focus:outline-none focus:shadow-outline bg-gradient-to-tl from-primary-500 to-secondary-500 bg-size-200 bg-pos-0 hover:bg-pos-100 transition-all duration-500"
>
<%= case @live_action do
:new -> gettext("Create")
:edit -> gettext("Save")
end %>
</button>
<%= if @live_action == :edit do %>
<%= link(gettext("Delete"),
to: "#",
phx_click: "delete",
phx_target: @myself,
phx_value_id: @embed.id,
data: [
confirm: gettext("This will delete the web content, are you sure?")
],
class:
"w-full lg:w-auto px-6 text-center text-white py-2 rounded-md tracking-wide font-bold focus:outline-none focus:shadow-outline bg-gradient-to-tl from-supporting-red-600 to-supporting-red-400 bg-size-200 bg-pos-0 hover:bg-pos-100 transition-all duration-500"
) %>
<% end %>
</div>
</.form>
</div>

View File

@@ -0,0 +1,84 @@
defmodule ClaperWeb.EventLive.EmbedComponent do
use ClaperWeb, :live_component
@impl true
def render(assigns) do
~H"""
<div>
<div
id="collapsed-embed"
class="bg-black py-3 px-6 text-black shadow-lg mx-auto rounded-full w-max hidden"
>
<div
class="block w-full h-full cursor-pointer"
phx-click={toggle_embed()}
phx-target={@myself}
>
<div class="text-white flex space-x-2 items-center">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
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>
<path d="M12 3a3 3 0 0 0 -3 3v12a3 3 0 0 0 3 3"></path>
<path d="M6 3a3 3 0 0 1 3 3v12a3 3 0 0 1 -3 3"></path>
<path d="M13 7h7a1 1 0 0 1 1 1v8a1 1 0 0 1 -1 1h-7"></path>
<path d="M5 7h-1a1 1 0 0 0 -1 1v8a1 1 0 0 0 1 1h1"></path>
<path d="M17 12h.01"></path>
<path d="M13 12h.01"></path>
</svg>
<span class="font-bold"><%= gettext("See current web content") %></span>
</div>
</div>
</div>
<div id="extended-embed" class="bg-black w-full py-3 px-6 text-black shadow-lg rounded-md">
<div
class="block w-full h-full cursor-pointer"
phx-click={toggle_embed()}
phx-target={@myself}
>
<div id="embed-pane" class="float-right mt-2">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-8 w-8 text-white"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="2"
>
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</div>
<p class="text-xs text-gray-500 my-1"><%= gettext("Current web content") %></p>
<p class="text-white text-lg font-semibold mb-4"><%= @embed.title %></p>
</div>
<div class="flex flex-col space-y-3">
<%= raw(@embed.content) %>
</div>
</div>
</div>
"""
end
def toggle_embed(js \\ %JS{}) do
js
|> JS.toggle(
out: "animate__animated animate__zoomOut",
in: "animate__animated animate__zoomIn",
to: "#collapsed-embed",
time: 50
)
|> JS.toggle(
out: "animate__animated animate__zoomOut",
in: "animate__animated animate__zoomIn",
to: "#extended-embed"
)
end
end

View File

@@ -161,7 +161,7 @@ defmodule ClaperWeb.EventLive.EventFormComponent do
|> Map.put("user_id", socket.assigns.current_user.id)
) do
{:ok, event} ->
with e <- Events.get_event!(event.uuid, [:presentation_file]) do
with e <- Events.get_event!(event.uuid, [:presentation_file, :leaders]) do
Task.Supervisor.async_nolink(Claper.TaskSupervisor, fn ->
Claper.Tasks.Converter.convert(
socket.assigns.current_user.id,
@@ -171,6 +171,14 @@ defmodule ClaperWeb.EventLive.EventFormComponent do
e.presentation_file.id
)
end)
Enum.each(e.leaders, fn leader ->
Claper.Accounts.LeaderNotifier.deliver_event_invitation(
e.name,
leader.email,
Routes.event_index_url(socket, :index)
)
end)
end
{:noreply,
@@ -188,9 +196,11 @@ defmodule ClaperWeb.EventLive.EventFormComponent do
socket.assigns.event,
event_params
) do
{:ok, _event} ->
{:ok, event} ->
handle_file_conversion(socket, hash, ext)
send_email_to_leaders(socket, event)
{:noreply,
socket
|> put_flash(:info, gettext("Updated successfully"))
@@ -225,6 +235,24 @@ defmodule ClaperWeb.EventLive.EventFormComponent do
Application.get_env(:claper, :storage_dir)
end
defp send_email_to_leaders(socket, event) do
with e <- Events.get_event!(event.uuid, [:leaders]) do
# Get the leaders before the update
previous_leaders = socket.assigns.event.leaders
Enum.each(e.leaders, fn leader ->
# Only send email if leader was not present before the update
unless Enum.member?(previous_leaders, leader) do
Claper.Accounts.LeaderNotifier.deliver_event_invitation(
e.name,
leader.email,
Routes.event_index_url(socket, :index)
)
end
end)
end
end
def error_to_string(:too_large), do: gettext("Your file is too large")
def error_to_string(:not_accepted), do: gettext("You have selected an incorrect file type")
def error_to_string(:external_client_failure), do: gettext("Upload failed")

View File

@@ -89,12 +89,32 @@ defmodule ClaperWeb.EventLive.FormComponent do
<% end %>
</div>
<button
type="submit"
class="px-3 py-2 text-white font-semibold bg-primary-500 hover:bg-primary-600 rounded-md my-5"
>
<%= if is_nil(assigns.current_form_submit), do: gettext("Submit"), else: gettext("Edit") %>
</button>
<div class="flex items-center gap-4">
<button
type="submit"
class="px-3 py-2 text-white font-semibold bg-primary-500 hover:bg-primary-600 rounded-md my-5"
>
<%= if is_nil(assigns.current_form_submit), do: gettext("Submit"), else: gettext("Edit") %>
</button>
<%= unless is_nil(assigns.current_form_submit) do %>
<div class="flex gap-1 text-green-500 text-sm">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" /><path d="M9 12l2 2l4 -4" />
</svg>
<span><%= gettext("Saved") %></span>
</div>
<% end %>
</div>
<% end %>
</div>
</div>

View File

@@ -4,6 +4,7 @@ defmodule ClaperWeb.EventLive.Manage do
alias ClaperWeb.Presence
alias Claper.Polls
alias Claper.Forms
alias Claper.Embeds
@impl true
def mount(%{"code" => code}, session, socket) do
@@ -40,9 +41,12 @@ defmodule ClaperWeb.EventLive.Manage do
|> assign(:attendees_nb, 1)
|> assign(:event, event)
|> assign(:state, event.presentation_file.presentation_state)
|> assign(:posts, list_posts(socket, event.uuid))
|> assign(:pinned_posts, list_pinned_posts(socket, event.uuid))
|> assign(:all_posts, list_all_posts(socket, event.uuid))
|> assign(:pinned_post_count, length(list_pinned_posts(socket, event.uuid)))
|> assign(:polls, list_polls(socket, event.presentation_file.id))
|> assign(:forms, list_forms(socket, event.presentation_file.id))
|> assign(:embeds, list_embeds(socket, event.presentation_file.id))
|> assign(:create, nil)
|> assign(:list_tab, :posts)
|> assign(:create_action, :new)
@@ -52,8 +56,9 @@ defmodule ClaperWeb.EventLive.Manage do
})
|> poll_at_position(false)
|> form_at_position(false)
|> embed_at_position(false)
{:ok, socket, temporary_assigns: [posts: [], form_submits: []]}
{:ok, socket, temporary_assigns: [all_posts: [], pinned_posts: [], form_submits: []]}
end
end
@@ -72,27 +77,50 @@ defmodule ClaperWeb.EventLive.Manage do
@impl true
def handle_info({:post_created, post}, socket) do
{:noreply,
socket |> update(:posts, fn posts -> [post | posts] end) |> push_event("scroll", %{})}
socket
|> assign(:all_posts, [post | socket.assigns.all_posts])
|> push_event("scroll", %{})}
end
@impl true
def handle_info({:post_updated, post}, socket) do
{:noreply, socket |> update(:posts, fn posts -> [post | posts] end)}
def handle_info({:post_updated, updated_post}, socket) do
{:noreply,
socket
|> update(:all_posts, fn posts -> [updated_post | posts] end)
|> update(:pinned_posts, fn posts -> [updated_post | posts] end)}
end
@impl true
def handle_info({:reaction_added, post}, socket) do
{:noreply, socket |> update(:posts, fn posts -> [post | posts] end)}
def handle_info({:post_deleted, deleted_post}, socket) do
{:noreply,
socket
|> update(:all_posts, fn posts -> [deleted_post | posts] end)
|> update(:pinned_posts, fn posts -> [deleted_post | posts] end)
|> update(:pinned_post_count, fn pinned_post_count ->
pinned_post_count - if deleted_post.pinned, do: 1, else: 0
end)}
end
@impl true
def handle_info({:reaction_removed, post}, socket) do
{:noreply, socket |> update(:posts, fn posts -> [post | posts] end)}
def handle_info({:post_pinned, post}, socket) do
updated_socket =
socket
|> update(:all_posts, fn all_posts -> [post | all_posts] end)
|> update(:pinned_posts, fn pinned_posts -> [post | pinned_posts] end)
|> assign(:pinned_post_count, socket.assigns.pinned_post_count + 1)
{:noreply, updated_socket}
end
@impl true
def handle_info({:post_deleted, post}, socket) do
{:noreply, socket |> update(:posts, fn posts -> [post | posts] end)}
def handle_info({:post_unpinned, post}, socket) do
updated_socket =
socket
|> update(:all_posts, fn all_posts -> [post | all_posts] end)
|> update(:pinned_posts, fn pinned_posts -> [post | pinned_posts] end)
|> assign(:pinned_post_count, socket.assigns.pinned_post_count - 1)
{:noreply, updated_socket}
end
@impl true
@@ -128,6 +156,21 @@ defmodule ClaperWeb.EventLive.Manage do
{:noreply, socket |> assign(:current_poll, poll)}
end
@impl true
def handle_info({:embed_updated, embed}, socket) do
{:noreply,
socket
|> update(:current_embed, fn _current_embed -> embed end)}
end
@impl true
def handle_info(
{:current_embed, embed},
socket
) do
{:noreply, socket |> assign(:current_embed, embed)}
end
@impl true
def handle_info(_, socket) do
{:noreply, socket}
@@ -159,7 +202,8 @@ defmodule ClaperWeb.EventLive.Manage do
socket
|> assign(:state, new_state)
|> poll_at_position
|> form_at_position}
|> form_at_position
|> embed_at_position}
end
@impl true
@@ -185,13 +229,15 @@ defmodule ClaperWeb.EventLive.Manage do
end
end
def handle_event("poll-set-default", %{"id" => id}, socket) do
def handle_event("poll-set-active", %{"id" => id}, socket) do
Forms.disable_all(socket.assigns.event.presentation_file.id, socket.assigns.state.position)
Embeds.disable_all(socket.assigns.event.presentation_file.id, socket.assigns.state.position)
Polls.set_default(
Polls.set_status(
id,
socket.assigns.event.presentation_file.id,
socket.assigns.state.position
socket.assigns.state.position,
true
)
poll = Polls.get_poll!(id)
@@ -208,19 +254,28 @@ defmodule ClaperWeb.EventLive.Manage do
{:current_form, nil}
)
Phoenix.PubSub.broadcast(
Claper.PubSub,
"event:#{socket.assigns.event.uuid}",
{:current_embed, nil}
)
{:noreply,
socket
|> assign(:polls, list_polls(socket, socket.assigns.event.presentation_file.id))
|> assign(:forms, list_forms(socket, socket.assigns.event.presentation_file.id))}
|> assign(:forms, list_forms(socket, socket.assigns.event.presentation_file.id))
|> assign(:embeds, list_embeds(socket, socket.assigns.event.presentation_file.id))}
end
def handle_event("form-set-default", %{"id" => id}, socket) do
def handle_event("form-set-active", %{"id" => id}, socket) do
Polls.disable_all(socket.assigns.event.presentation_file.id, socket.assigns.state.position)
Embeds.disable_all(socket.assigns.event.presentation_file.id, socket.assigns.state.position)
Forms.set_default(
Forms.set_status(
id,
socket.assigns.event.presentation_file.id,
socket.assigns.state.position
socket.assigns.state.position,
true
)
form = Forms.get_form!(id)
@@ -237,12 +292,114 @@ defmodule ClaperWeb.EventLive.Manage do
{:current_poll, nil}
)
Phoenix.PubSub.broadcast(
Claper.PubSub,
"event:#{socket.assigns.event.uuid}",
{:current_embed, nil}
)
{:noreply,
socket
|> assign(:polls, list_polls(socket, socket.assigns.event.presentation_file.id))
|> assign(:forms, list_forms(socket, socket.assigns.event.presentation_file.id))
|> assign(:embeds, list_embeds(socket, socket.assigns.event.presentation_file.id))}
end
def handle_event("embed-set-active", %{"id" => id}, socket) do
Polls.disable_all(socket.assigns.event.presentation_file.id, socket.assigns.state.position)
Forms.disable_all(socket.assigns.event.presentation_file.id, socket.assigns.state.position)
Embeds.set_status(
id,
socket.assigns.event.presentation_file.id,
socket.assigns.state.position,
true
)
embed = Embeds.get_embed!(id)
Phoenix.PubSub.broadcast(
Claper.PubSub,
"event:#{socket.assigns.event.uuid}",
{:current_embed, embed}
)
Phoenix.PubSub.broadcast(
Claper.PubSub,
"event:#{socket.assigns.event.uuid}",
{:current_poll, nil}
)
Phoenix.PubSub.broadcast(
Claper.PubSub,
"event:#{socket.assigns.event.uuid}",
{:current_form, nil}
)
{:noreply,
socket
|> assign(:polls, list_polls(socket, socket.assigns.event.presentation_file.id))
|> assign(:forms, list_forms(socket, socket.assigns.event.presentation_file.id))
|> assign(:embeds, list_embeds(socket, socket.assigns.event.presentation_file.id))}
end
def handle_event("poll-set-inactive", %{"id" => id}, socket) do
Polls.set_status(
id,
socket.assigns.event.presentation_file.id,
socket.assigns.state.position,
false
)
Phoenix.PubSub.broadcast(
Claper.PubSub,
"event:#{socket.assigns.event.uuid}",
{:current_poll, nil}
)
{:noreply,
socket
|> assign(:polls, list_polls(socket, socket.assigns.event.presentation_file.id))}
end
def handle_event("form-set-inactive", %{"id" => id}, socket) do
Forms.set_status(
id,
socket.assigns.event.presentation_file.id,
socket.assigns.state.position,
false
)
Phoenix.PubSub.broadcast(
Claper.PubSub,
"event:#{socket.assigns.event.uuid}",
{:current_form, nil}
)
{:noreply,
socket
|> assign(:forms, list_forms(socket, socket.assigns.event.presentation_file.id))}
end
def handle_event("embed-set-inactive", %{"id" => id}, socket) do
Embeds.set_status(
id,
socket.assigns.event.presentation_file.id,
socket.assigns.state.position,
false
)
Phoenix.PubSub.broadcast(
Claper.PubSub,
"event:#{socket.assigns.event.uuid}",
{:current_embed, nil}
)
{:noreply,
socket
|> assign(:embeds, list_embeds(socket, socket.assigns.event.presentation_file.id))}
end
@impl true
def handle_event(
"ban",
@@ -254,6 +411,12 @@ defmodule ClaperWeb.EventLive.Manage do
ban(attendee_identifier, socket)
end
@impl true
def handle_event("pin", %{"id" => id}, socket) do
post = Claper.Posts.get_post!(id, [:event])
pin(post, socket)
end
@impl true
def handle_event(
"ban",
@@ -333,6 +496,23 @@ defmodule ClaperWeb.EventLive.Manage do
{:noreply, socket |> assign(:state, new_state)}
end
@impl true
def handle_event(
"checked",
%{"key" => "show_only_pinned", "value" => value},
%{assigns: %{event: _event, state: state}} = socket
) do
{:ok, new_state} =
Claper.Presentations.update_presentation_state(
state,
%{
:show_only_pinned => value
}
)
{:noreply, socket |> assign(:state, new_state)}
end
@impl true
def handle_event(
"checked",
@@ -351,11 +531,19 @@ defmodule ClaperWeb.EventLive.Manage do
end
@impl true
def handle_event("delete", %{"event-id" => event_id, "id" => id}, socket) do
def handle_event("delete", %{"id" => id}, socket) do
post = Claper.Posts.get_post!(id, [:event])
{:ok, _} = Claper.Posts.delete_post(post)
{:noreply, assign(socket, :posts, list_posts(socket, event_id))}
updated_socket =
if post.pinned do
assign(socket, :pinned_posts, list_pinned_posts(socket, socket.assigns.event.uuid))
assign(socket, :all_posts, list_all_posts(socket, socket.assigns.event.uuid))
else
assign(socket, :all_posts, list_all_posts(socket, socket.assigns.event.uuid))
end
{:noreply, updated_socket}
end
@impl true
@@ -378,7 +566,9 @@ defmodule ClaperWeb.EventLive.Manage do
socket =
case tab do
"posts" ->
assign(socket, :posts, list_posts(socket, socket.assigns.event.uuid))
socket
|> assign(:pinned_posts, list_pinned_posts(socket, socket.assigns.event.uuid))
|> assign(:all_posts, list_all_posts(socket, socket.assigns.event.uuid))
"forms" ->
assign(
@@ -386,6 +576,10 @@ defmodule ClaperWeb.EventLive.Manage do
:form_submits,
list_form_submits(socket, socket.assigns.event.presentation_file.id)
)
"pinned_posts" ->
socket
|> assign(:pinned_posts, list_pinned_posts(socket, socket.assigns.event.uuid))
end
{:noreply, socket}
@@ -459,6 +653,12 @@ defmodule ClaperWeb.EventLive.Manage do
})
end
defp apply_action(socket, :add_embed, _params) do
socket
|> assign(:create, "embed")
|> assign(:embed, %Embeds.Embed{})
end
defp apply_action(socket, :import, _params) do
socket
|> assign(:create, "import")
@@ -474,6 +674,15 @@ defmodule ClaperWeb.EventLive.Manage do
|> assign(:form, form)
end
defp apply_action(socket, :edit_embed, %{"id" => id}) do
embed = Embeds.get_embed!(id)
socket
|> assign(:create, "embed")
|> assign(:create_action, :edit)
|> assign(:embed, embed)
end
defp poll_at_position(
%{assigns: %{event: event, state: state}} = socket,
broadcast \\ true
@@ -516,6 +725,33 @@ defmodule ClaperWeb.EventLive.Manage do
end
end
defp pin(post, socket) do
{:ok, _updated_post} = Claper.Posts.toggle_pin_post(post)
{:noreply, socket}
end
defp embed_at_position(
%{assigns: %{event: event, state: state}} = socket,
broadcast \\ true
) do
with embed <-
Claper.Embeds.get_embed_current_position(
event.presentation_file.id,
state.position
) do
if broadcast do
Phoenix.PubSub.broadcast(
Claper.PubSub,
"event:#{event.uuid}",
{:current_embed, embed}
)
end
socket |> assign(:current_embed, embed)
end
end
defp ban(user, %{assigns: %{event: event, state: state}} = socket) do
{:ok, new_state} =
Claper.Presentations.update_presentation_state(state, %{
@@ -531,7 +767,11 @@ defmodule ClaperWeb.EventLive.Manage do
{:noreply, socket |> assign(:state, new_state)}
end
defp list_posts(_socket, event_id) do
defp list_pinned_posts(_socket, event_id) do
Claper.Posts.list_pinned_posts(event_id, [:event, :reactions])
end
defp list_all_posts(_socket, event_id) do
Claper.Posts.list_posts(event_id, [:event, :reactions])
end
@@ -543,6 +783,10 @@ defmodule ClaperWeb.EventLive.Manage do
Claper.Forms.list_forms(presentation_file_id)
end
defp list_embeds(_socket, presentation_file_id) do
Claper.Embeds.list_embeds(presentation_file_id)
end
defp list_form_submits(_socket, presentation_file_id) do
Claper.Forms.list_form_submits(presentation_file_id)
end

View File

@@ -1,7 +1,8 @@
<div
id="manager"
class="h-screen max-h-screen flex flex-col"
x-data={"{date: moment.utc('#{@event.expired_at}').local().format('lll')}"}
x-data={"{date:
moment.utc('#{@event.expired_at}').local().format('lll')}"}
phx-hook="Manager"
data-max-page={@event.presentation_file.length}
data-current-page={@state.position}
@@ -117,7 +118,8 @@
<div
id="add-modal"
class={"#{if !@create, do: 'hidden'} fixed z-30 inset-0 overflow-y-auto p-4 sm:p-6 md:p-24 transform transition-all duration-150"}
class={"#{if !@create, do: 'hidden' } fixed z-30 inset-0 overflow-y-auto p-4 sm:p-6 md:p-24
transform transition-all duration-150"}
role="dialog"
aria-modal="true"
>
@@ -145,7 +147,7 @@
</button>
<div id="modal-content" class="bg-gray-100">
<%= if @create == nil do %>
<%= if @create==nil do %>
<ul class="scroll-py-3 overflow-y-auto p-3" id="options" role="listbox">
<li id="option-1" role="option" tabindex="-1">
<a
@@ -171,7 +173,9 @@
</svg>
</div>
<div class="ml-4 flex-auto text-left">
<p class="font-medium text-gray-700"><%= gettext("Poll") %></p>
<p class="font-medium text-gray-700">
<%= gettext("Poll") %>
</p>
<p class="text-gray-500">
<%= gettext("Add poll to know opinion of your public.") %>
</p>
@@ -208,16 +212,49 @@
</svg>
</div>
<div class="ml-4 flex-auto text-left">
<p class="font-medium text-gray-700"><%= gettext("Form") %></p>
<p class="font-medium text-gray-700">
<%= gettext("Form") %>
</p>
<p class="text-gray-500">
<%= gettext("Add form to collect data from your public.") %>
</p>
</div>
</a>
</li>
<li id="option-3" role="option" tabindex="-1">
<a
data-phx-link="patch"
data-phx-link-state="push"
href={Routes.event_manage_path(@socket, :add_embed, @event.code)}
class="group flex select-none rounded-xl p-3 w-full hover:bg-gray-200 cursor-pointer"
>
<div class="flex h-12 w-12 flex-none text-white items-center justify-center rounded-lg bg-gradient-to-br from-primary-500 to-secondary-500">
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-6 h-6"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M14.25 9.75L16.5 12l-2.25 2.25m-4.5 0L7.5 12l2.25-2.25M6 20.25h12A2.25 2.25 0 0020.25 18V6A2.25 2.25 0 0018 3.75H6A2.25 2.25 0 003.75 6v12A2.25 2.25 0 006 20.25z"
/>
</svg>
</div>
<div class="ml-4 flex-auto text-left">
<p class="font-medium text-gray-700"><%= gettext("Web content") %></p>
<p class="text-gray-500">
<%= gettext("Add a Youtube video or any web content.") %>
</p>
</div>
</a>
</li>
</ul>
<%= if (length @polls) == 0 && (length @forms) == 0 do %>
<%= if (length @polls)==0 && (length @forms)==0 do %>
<div class="mt-10">
<a
data-phx-link="patch"
@@ -248,7 +285,7 @@
<% end %>
<% end %>
<%= if @create == "poll" do %>
<%= if @create=="poll" do %>
<div class="scroll-py-3 overflow-y-auto bg-gray-100 p-3">
<p class="text-xl font-bold">
<%= case @create_action do
@@ -269,7 +306,7 @@
</div>
<% end %>
<%= if @create == "form" do %>
<%= if @create=="form" do %>
<div class="scroll-py-3 overflow-y-auto bg-gray-100 p-3">
<p class="text-xl font-bold">
<%= case @create_action do
@@ -290,9 +327,32 @@
</div>
<% end %>
<%= if @create == "embed" do %>
<div class="scroll-py-3 overflow-y-auto bg-gray-100 p-3">
<p class="text-xl font-bold">
<%= case @create_action do
:new -> gettext("New web content")
:edit -> gettext("Edit web content")
end %>
</p>
<.live_component
module={ClaperWeb.EmbedLive.FormComponent}
id="embed-create"
event_uuid={@event.uuid}
presentation_file={@event.presentation_file}
embed={@embed}
live_action={@create_action}
position={@state.position}
return_to={Routes.event_manage_path(@socket, :show, @event.code)}
/>
</div>
<% end %>
<%= if @create == "import" do %>
<div class="scroll-py-3 overflow-y-auto bg-gray-100 p-3">
<p class="text-xl font-bold"><%= gettext("Select presentation") %></p>
<p class="text-xl font-bold">
<%= gettext("Select presentation") %>
</p>
<ul>
<%= for event <- @events do %>
<li class="my-3">
@@ -315,7 +375,9 @@
d="M3 16.5v2.25A2.25 2.25 0 005.25 21h13.5A2.25 2.25 0 0021 18.75V16.5M16.5 12L12 16.5m0 0L7.5 12m4.5 4.5V3"
/>
</svg>
<span><%= event.name %></span>
<span>
<%= event.name %>
</span>
</button>
</li>
<% end %>
@@ -330,7 +392,7 @@
<div class="bg-gray-100 pb-10 md:col-span-2 overflow-y-auto">
<div class="flex flex-col justify-center items-center text-center">
<%= for index <- 0..@event.presentation_file.length-1 do %>
<%= if @state.position == index && @state.position > 0 do %>
<%= if @state.position==index && @state.position> 0 do %>
<button
phx-click="current-page"
phx-value-page={index - 1}
@@ -350,7 +412,8 @@
<% end %>
<div
class={"#{if @state.position == index, do: 'shadow-xl bg-white', else: 'opacity-50 bg-gray-100'} transition-all pb-5"}
class={"#{if @state.position==index, do: 'shadow-xl bg-white' , else: 'opacity-50 bg-gray-100' }
transition-all pb-5"}
id={"slide-preview-#{index}"}
>
<button
@@ -366,7 +429,9 @@
<% else %>
<img
class="w-1/3 mx-auto"
src={"https://#{Application.get_env(:claper, :presentations) |> Keyword.get(:aws_bucket)}.s3.#{Application.get_env(:ex_aws, :region)}.amazonaws.com/presentations/#{@event.presentation_file.hash}/#{index+1}.jpg"}
src={"https://#{Application.get_env(:claper, :presentations) |>
Keyword.get(:aws_bucket)}.s3.#{Application.get_env(:ex_aws,
:region)}.amazonaws.com/presentations/#{@event.presentation_file.hash}/#{index+1}.jpg"}
/>
<% end %>
</button>
@@ -392,11 +457,17 @@
</div>
<div class="flex space-x-2">
<span>
<span class="font-semibold"><%= gettext "Poll" %></span>: <%= poll.title %>
<span class="font-semibold">
<%= gettext "Poll" %>
</span>: <%= poll.title %>
</span>
<%= if @state.position == index do %>
<%= if @state.position==index do %>
<%= if poll.enabled do %>
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-supporting-green-100 text-supporting-green-800">
<button
phx-click="poll-set-inactive"
phx-value-id={poll.id}
class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-supporting-green-100 text-supporting-green-800"
>
<svg
style="--animate-duration: 10s;"
class="mr-1.5 h-2 w-2 text-supporting-green-400 animate__animated animate__flash animate__infinite"
@@ -406,10 +477,10 @@
<circle cx="4" cy="4" r="3" />
</svg>
<%= gettext("Active") %>
</span>
</button>
<% else %>
<button
phx-click="poll-set-default"
phx-click="poll-set-active"
phx-value-id={poll.id}
class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-primary-100 text-primary-800"
>
@@ -468,11 +539,17 @@
</div>
<div class="flex space-x-2">
<span>
<span class="font-semibold"><%= gettext "Form" %></span>: <%= form.title %>
<span class="font-semibold">
<%= gettext "Form" %>
</span>: <%= form.title %>
</span>
<%= if @state.position == index do %>
<%= if @state.position==index do %>
<%= if form.enabled do %>
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-supporting-green-100 text-supporting-green-800">
<button
phx-click="form-set-inactive"
phx-value-id={form.id}
class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-supporting-green-100 text-supporting-green-800"
>
<svg
style="--animate-duration: 10s;"
class="mr-1.5 h-2 w-2 text-supporting-green-400 animate__animated animate__flash animate__infinite"
@@ -482,10 +559,10 @@
<circle cx="4" cy="4" r="3" />
</svg>
<%= gettext("Active") %>
</span>
</button>
<% else %>
<button
phx-click="form-set-default"
phx-click="form-set-active"
phx-value-id={form.id}
class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-primary-100 text-primary-800"
>
@@ -518,16 +595,92 @@
</div>
<div class="h-10 border border-gray-300"></div>
<% end %>
<%= for embed<- Enum.filter(@embeds, fn embed -> embed.position == index end) do %>
<div class="flex space-x-2 items-center">
<div class="flex h-10 w-10 flex-none text-white items-center justify-center rounded-lg bg-gradient-to-br from-primary-500 to-secondary-500">
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="2"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M14.25 9.75L16.5 12l-2.25 2.25m-4.5 0L7.5 12l2.25-2.25M6 20.25h12A2.25 2.25 0 0020.25 18V6A2.25 2.25 0 0018 3.75H6A2.25 2.25 0 003.75 6v12A2.25 2.25 0 006 20.25z"
/>
</svg>
</div>
<div class="flex space-x-2">
<span>
<span class="font-semibold"><%= gettext "Web content" %></span>: <%= embed.title %>
</span>
<%= if @state.position == index do %>
<%= if embed.enabled do %>
<button
phx-click="embed-set-inactive"
phx-value-id={embed.id}
class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-supporting-green-100 text-supporting-green-800"
>
<svg
style="--animate-duration: 10s;"
class="mr-1.5 h-2 w-2 text-supporting-green-400 animate__animated animate__flash animate__infinite"
fill="currentColor"
viewBox="0 0 8 8"
>
<circle cx="4" cy="4" r="3" />
</svg>
<%= gettext("Active") %>
</button>
<% else %>
<button
phx-click="embed-set-active"
phx-value-id={embed.id}
class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-primary-100 text-primary-800"
>
<%= gettext("Set active") %>
</button>
<% end %>
<a
data-phx-link="patch"
data-phx-link-state="push"
href={
Routes.event_manage_path(@socket, :edit_embed, @event.code, embed.id)
}
class="text-xs text-primary-500"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
stroke-width="2"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z"
/>
</svg>
</a>
<% end %>
</div>
</div>
<div class="h-10 border border-gray-300"></div>
<% end %>
</div>
<%= if @state.position == index do %>
<%= if @state.position==index do %>
<button class="underline" phx-click={toggle_add_modal()}>
<%= gettext("Add interaction") %>
</button>
<% end %>
</div>
<%= if @state.position == index && @state.position < @event.presentation_file.length - 1 do %>
<%= if @state.position==index && @state.position < @event.presentation_file.length - 1 do %>
<button
phx-click="current-page"
phx-value-page={index + 1}
@@ -549,13 +702,27 @@
</div>
</div>
<div class="grid grid-cols-1 grid-rows-2 md:grid-rows-3">
<div class="bg-gray-200 md:row-span-2">
<ul class="fixed z-20 flex items-center bg-gray-200 space-x-3 px-2 w-full py-2">
<li class={"rounded-md #{if @list_tab == :posts, do: 'bg-secondary-600 text-white', else: 'bg-white text-gray-600' } px-2 py-0.5 text-sm shadow-sm"}>
<div class="grid grid-cols-1 grid-rows-2 md:grid-rows-3" style="height: 100%;">
<div class="bg-gray-200 md:row-span-2 border-2">
<ul
id="menu"
phx-update="replace"
class="fixed z-20 flex items-center bg-gray-200 space-x-3 px-2 w-full py-2"
>
<li class={"rounded-md #{if @list_tab==:posts, do: 'bg-secondary-600 text-white' ,
else: 'bg-white text-gray-600' } px-2 py-0.5 text-sm shadow-sm"}>
<%= link(gettext("Messages"), to: "#", phx_click: "list-tab", phx_value_tab: :posts) %>
</li>
<li class={"rounded-md #{if @list_tab == :forms, do: 'bg-secondary-600 text-white', else: 'bg-white text-gray-600' } px-2 py-0.5 text-sm shadow-sm"}>
<li class={"rounded-md #{if @list_tab==:pinned_posts, do: 'bg-secondary-600 text-white' ,
else: 'bg-white text-gray-600' } px-2 py-0.5 text-sm shadow-sm"}>
<%= link(gettext("Pinned messages") <> " (#{@pinned_post_count})",
to: "#",
phx_click: "list-tab",
phx_value_tab: :pinned_posts
) %>
</li>
<li class={"rounded-md #{if @list_tab==:forms, do: 'bg-secondary-600 text-white' ,
else: 'bg-white text-gray-600' } px-2 py-0.5 text-sm shadow-sm"}>
<%= link(gettext("Form submissions"),
to: "#",
phx_click: "list-tab",
@@ -563,9 +730,13 @@
) %>
</li>
</ul>
<%= if @list_tab == :posts do %>
<%= if Enum.count(@posts) == 0 do %>
<div class="text-center h-full flex flex-col space-y-5 items-center justify-center text-gray-400">
<%= if @list_tab==:posts do %>
<%= if Enum.count(@all_posts)==0 && Enum.count(@pinned_posts)==0 do %>
<div
class="text-center flex flex-col space-y-5 items-center justify-center text-gray-400"
style="height: 100%;"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-36 w-36"
@@ -581,112 +752,338 @@
/>
</svg>
<p class="text-lg"><%= gettext("Messages from attendees will appear here.") %></p>
<p class="text-lg">
<%= gettext("Messages from attendees will appear here.") %>
</p>
</div>
<% end %>
<div
id="post-list"
class={"overflow-y-auto #{if Enum.count(@posts) > 0, do: 'max-h-full'} pb-5 pt-8 px-5"}
phx-update="append"
data-posts-nb={Enum.count(@posts)}
phx-hook="ScrollIntoDiv"
data-target="#post-list"
id="x"
class={"overflow-y-auto #{if Enum.any?(@pinned_posts) or Enum.any?(@all_posts), do: 'h-full', else: 'h-1/2'}"}
>
<%= for post <- @posts do %>
<div class={if post.__meta__.state == :deleted, do: "hidden"} id={"#{post.id}-post"}>
<div class="px-4 pb-2 pt-3 rounded-b-lg rounded-tr-lg bg-white relative shadow-md text-black break-all mt-4">
<div class="float-right mr-1">
<%= if post.attendee_identifier do %>
<div
id="post-list"
class={"overflow-y-auto #{if Enum.count(@all_posts)> 0, do: ''} pb-5 pt-8 px-5"}
phx-update="append"
data-posts-nb={Enum.count(@all_posts)}
phx-hook="ScrollIntoDiv"
data-target="#post-list"
>
<%= for post <- @all_posts do %>
<div
class={if post.__meta__.state == :deleted, do: "hidden"}
id={"#{post.id}-post"}
>
<div class="px-4 pb-2 pt-3 rounded-b-lg rounded-tr-lg bg-white relative shadow-md text-black break-all mt-4">
<div class="float-right mr-1">
<%= if post.attendee_identifier do %>
<span class="text-yellow-500">
<%= link(
if post.pinned do
gettext("Unpin")
else
gettext("Pin")
end,
to: "#",
phx_click: "pin",
phx_value_id: post.uuid,
phx_value_event_id: @event.uuid
) %>
</span>
/
<span class="text-red-500">
<%= link(gettext("Ban"),
to: "#",
phx_click: "ban",
phx_value_attendee_identifier: post.attendee_identifier,
data: [
confirm:
gettext(
"Blocking this user will delete all his messages and he will not be able to join again, confirm ?"
)
]
) %>
</span>
/
<% else %>
<span class="text-yellow-500">
<%= link(
if post.pinned do
gettext("Unpin")
else
gettext("Pin")
end,
to: "#",
phx_click: "pin",
phx_value_id: post.uuid,
phx_value_event_id: @event.uuid
) %>
</span>
/
<span class="text-red-500">
<%= link(gettext("Ban"),
to: "#",
phx_click: "ban",
phx_value_user_id: post.user_id,
data: [
confirm:
gettext(
"Blocking this user will delete all his messages and he will not be able to join again, confirm ?"
)
]
) %>
</span>
/
<% end %>
<span class="text-red-500">
<%= link(gettext("Ban"),
<%= link(gettext("Delete"),
to: "#",
phx_click: "ban",
phx_value_attendee_identifier: post.attendee_identifier,
data: [
confirm:
gettext(
"Blocking this user will delete all his messages and he will not be able to join again, confirm ?"
)
]
phx_click: "delete",
phx_value_id: post.uuid,
phx_value_event_id: @event.uuid
) %>
</span>
/
<% else %>
<span class="text-red-500">
<%= link(gettext("Ban"),
to: "#",
phx_click: "ban",
phx_value_user_id: post.user_id,
data: [
confirm:
gettext(
"Blocking this user will delete all his messages and he will not be able to join again, confirm ?"
)
]
) %>
</span>
/
<% end %>
<span class="text-red-500">
<%= link(gettext("Delete"),
to: "#",
phx_click: "delete",
phx_value_id: post.uuid,
phx_value_event_id: @event.uuid
) %>
</span>
</div>
</div>
<div class="flex space-x-3 items-center">
<%= if post.attendee_identifier do %>
<img
class="h-8 w-8"
src={"https://avatars.dicebear.com/api/identicon/#{post.attendee_identifier}.svg"}
/>
<% else %>
<img
class="h-8 w-8"
src={"https://avatars.dicebear.com/api/identicon/#{post.user_id}.svg"}
/>
<% end %>
<div class="flex flex-col">
<%= if post.name do %>
<p class="text-black text-sm font-semibold mr-2"><%= post.name %></p>
<div class="flex space-x-3 items-center">
<%= if post.attendee_identifier do %>
<img
class="h-8 w-8"
src={"https://api.dicebear.com/7.x/personas/svg?seed=#{post.attendee_identifier}"}
/>
<% else %>
<img
class="h-8 w-8"
src={"https://api.dicebear.com/7.x/personas/svg?seed=#{post.user_id}"}
/>
<% end %>
<p class="text-xl"><%= post.body %></p>
<div class="flex flex-col">
<%= if post.name do %>
<p class="text-black text-sm font-semibold mr-2">
<%= post.name %>
</p>
<% end %>
<p class="text-xl">
<%= post.body %>
</p>
</div>
</div>
<%= if post.like_count> 0 || post.love_count > 0 || post.lol_count > 0 do %>
<div class="flex h-6 space-x-2 text-base text-gray-500 pb-3 items-center mt-5">
<div class="flex items-center">
<%= if post.like_count> 0 do %>
<img src="/images/icons/thumb.svg" class="h-4" />
<span class="ml-1">
<%= post.like_count %>
</span>
<% end %>
</div>
<div class="flex items-center">
<%= if post.love_count> 0 do %>
<img src="/images/icons/heart.svg" class="h-4" />
<span class="ml-1">
<%= post.love_count %>
</span>
<% end %>
</div>
<div class="flex items-center">
<%= if post.lol_count> 0 do %>
<img src="/images/icons/laugh.svg" class="h-4" />
<span class="ml-1">
<%= post.lol_count %>
</span>
<% end %>
</div>
</div>
<% end %>
</div>
</div>
<% end %>
</div>
<!-- The div below encompasses the 2 post lists -->
</div>
<% end %>
<%= if @list_tab == :pinned_posts do %>
<%= if Enum.count(@pinned_posts) == 0 do %>
<div
class="text-center flex flex-col space-y-5 items-center justify-center text-gray-400"
style="height: 100%;"
>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-36 w-36"
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none" /><path d="M15 4.5l-4 4l-4 1.5l-1.5 1.5l7 7l1.5 -1.5l1.5 -4l4 -4" /><path d="M9 15l-4.5 4.5" /><path d="M14.5 4l5.5 5.5" />
</svg>
<p class="text-lg">
<%= gettext("Pinned messages will appear here.") %>
</p>
</div>
<% end %>
<div
id="x-pinned"
class={"overflow-y-auto #{if Enum.any?(@pinned_posts), do: 'h-full', else: 'h-1/2'}"}
>
<%= if Enum.any?(@pinned_posts) do %>
<div
id="pinned-post-list"
class="overflow-y-auto pb-5 pt-8 px-5"
phx-update="append"
data-posts-nb={Enum.count(@pinned_posts)}
phx-hook="ScrollIntoDiv"
data-target="#pinned-post-list"
>
<%= for post <- @pinned_posts do %>
<div
class={if post.__meta__.state == :deleted || !post.pinned, do: "hidden"}
id={"#{post.id}-post"}
>
<div class="px-4 pb-2 pt-3 rounded-b-lg rounded-tr-lg bg-white relative shadow-md text-black break-all mt-4">
<div class="float-right mr-1">
<%= if post.attendee_identifier do %>
<span class="text-yellow-500">
<%= link(
if post.pinned do
gettext("Unpin")
else
gettext("Pin")
end,
to: "#",
phx_click: "pin",
phx_value_id: post.uuid,
phx_value_event_id: @event.uuid
) %>
</span>
/
<span class="text-red-500">
<%= link(gettext("Ban"),
to: "#",
phx_click: "ban",
phx_value_attendee_identifier: post.attendee_identifier,
data: [
confirm:
gettext(
"Blocking this user will delete all his messages and he will not be able to join again, confirm ?"
)
]
) %>
</span>
/
<% else %>
<span class="text-yellow-500">
<%= link(
if post.pinned do
gettext("Unpin")
else
gettext("Pin")
end,
to: "#",
phx_click: "pin",
phx_value_id: post.uuid,
phx_value_event_id: @event.uuid
) %>
</span>
/
<span class="text-red-500">
<%= link(gettext("Ban"),
to: "#",
phx_click: "ban",
phx_value_user_id: post.user_id,
data: [
confirm:
gettext(
"Blocking this user will delete all his messages and he will not be able to join again, confirm ?"
)
]
) %>
</span>
/
<% end %>
<span class="text-red-500">
<%= link(gettext("Delete"),
to: "#",
phx_click: "delete",
phx_value_id: post.uuid,
phx_value_event_id: @event.uuid
) %>
</span>
</div>
<div class="flex space-x-3 items-center">
<%= if post.attendee_identifier do %>
<img
class="h-8 w-8"
src={"https://api.dicebear.com/7.x/personas/svg?seed=#{post.attendee_identifier}"}
/>
<% else %>
<img
class="h-8 w-8"
src={"https://api.dicebear.com/7.x/personas/svg?seed=#{post.user_id}"}
/>
<% end %>
<div class="flex flex-col">
<%= if post.name do %>
<p class="text-black text-sm font-semibold mr-2">
<%= post.name %>
</p>
<% end %>
<p class="text-xl">
<%= post.body %>
</p>
</div>
</div>
<%= if post.like_count> 0 || post.love_count > 0 || post.lol_count > 0 do %>
<div class="flex h-6 space-x-2 text-base text-gray-500 pb-3 items-center mt-5">
<div class="flex items-center">
<%= if post.like_count> 0 do %>
<img src="/images/icons/thumb.svg" class="h-4" />
<span class="ml-1">
<%= post.like_count %>
</span>
<% end %>
</div>
<div class="flex items-center">
<%= if post.love_count> 0 do %>
<img src="/images/icons/heart.svg" class="h-4" />
<span class="ml-1">
<%= post.love_count %>
</span>
<% end %>
</div>
<div class="flex items-center">
<%= if post.lol_count> 0 do %>
<img src="/images/icons/laugh.svg" class="h-4" />
<span class="ml-1">
<%= post.lol_count %>
</span>
<% end %>
</div>
</div>
<% end %>
</div>
</div>
<%= if post.like_count > 0 || post.love_count > 0 || post.lol_count > 0 do %>
<div class="flex h-6 space-x-2 text-base text-gray-500 pb-3 items-center mt-5">
<div class="flex items-center">
<%= if post.like_count > 0 do %>
<img src="/images/icons/thumb.svg" class="h-4" />
<span class="ml-1"><%= post.like_count %></span>
<% end %>
</div>
<div class="flex items-center">
<%= if post.love_count > 0 do %>
<img src="/images/icons/heart.svg" class="h-4" />
<span class="ml-1"><%= post.love_count %></span>
<% end %>
</div>
<div class="flex items-center">
<%= if post.lol_count > 0 do %>
<img src="/images/icons/laugh.svg" class="h-4" />
<span class="ml-1"><%= post.lol_count %></span>
<% end %>
</div>
</div>
<% end %>
</div>
<% end %>
</div>
<% end %>
</div>
<% else %>
<%= if Enum.count(@form_submits) == 0 do %>
<% end %>
<%= if @list_tab==:forms do %>
<%= if Enum.count(@form_submits)==0 do %>
<div class="text-center h-full flex flex-col space-y-5 items-center justify-center text-gray-400">
<svg
xmlns="http://www.w3.org/2000/svg"
@@ -714,7 +1111,8 @@
<% end %>
<div
id="form-list"
class={"overflow-y-auto #{if Enum.count(@form_submits) > 0, do: 'max-h-full'} pb-5 pt-8 px-5"}
class={"overflow-y-auto #{if Enum.count(@form_submits)> 0, do: 'max-h-full'}
pb-5 pt-8 px-5"}
phx-update="append"
data-forms-nb={Enum.count(@form_submits)}
phx-hook="ScrollIntoDiv"
@@ -742,18 +1140,23 @@
<%= if submission.attendee_identifier do %>
<img
class="h-8 w-8"
src={"https://avatars.dicebear.com/api/identicon/#{submission.attendee_identifier}.svg"}
src={"https://api.dicebear.com/7.x/personas/svg?seed=#{submission.attendee_identifier}"}
/>
<% else %>
<img
class="h-8 w-8"
src={"https://avatars.dicebear.com/api/identicon/#{submission.user_id}.svg"}
src={"https://api.dicebear.com/7.x/personas/svg?seed=#{submission.user_id}"}
/>
<% end %>
<div>
<%= for res <- submission.response do %>
<p><strong><%= elem(res, 0) %>:</strong> <%= elem(res, 1) %></p>
<p>
<strong>
<%= elem(res, 0) %>:
</strong>
<%= elem(res, 1) %>
</p>
<% end %>
</div>
</div>
@@ -765,47 +1168,75 @@
</div>
<div class="w-full shadow-lg">
<div class="px-5 py-3 grid grid-cols-1 sm:grid-cols-2">
<div class="px-5 py-3 grid grid-cols-1 lg:grid-cols-2">
<div>
<span class="font-semibold text-lg"><%= gettext("On screen settings") %></span>
<span class="font-semibold text-lg">
<%= gettext("On screen settings") %>
</span>
<div class="flex space-x-2 items-center mt-3">
<ClaperWeb.Component.Input.check
key={:join_screen_visible}
checked={@state.join_screen_visible}
shortcut={if @create == nil, do: "Q", else: nil}
/>
<span><%= gettext("Show instructions") %></span>
<span><%= gettext("Show instructions") %><code class="pl-1">(Q)</code></span>
</div>
<div class="flex space-x-2 items-center mt-3">
<ClaperWeb.Component.Input.check key={:chat_visible} checked={@state.chat_visible} />
<span><%= gettext("Show messages") %></span>
<ClaperWeb.Component.Input.check
key={:chat_visible}
checked={@state.chat_visible}
shortcut={if @create == nil, do: "W", else: nil}
/>
<span><%= gettext("Show messages") %><code class="pl-1">(W)</code></span>
</div>
<div class={"#{if !@current_poll, do: 'opacity-50'} flex space-x-2 items-center mt-3"}>
<div class="flex space-x-2 items-center mt-3">
<ClaperWeb.Component.Input.check
key={:show_only_pinned}
checked={@state.show_only_pinned}
shortcut={if @create == nil, do: "E", else: nil}
/>
<span>
<%= gettext("Show only pinned messages") %><code class="pl-1">(E)</code>
</span>
</div>
<div class={"#{if !@current_poll, do: 'opacity-50' } flex space-x-2 items-center mt-3"}>
<ClaperWeb.Component.Input.check
key={:poll_visible}
disabled={!@current_poll}
checked={@state.poll_visible}
shortcut={if @create == nil, do: "R", else: nil}
/>
<span><%= gettext("Show poll results") %></span>
<span><%= gettext("Show poll results") %><code class="pl-1">(R)</code></span>
</div>
</div>
<div>
<span class="font-semibold text-lg"><%= gettext("Attendees settings") %></span>
<span class="font-semibold text-lg">
<%= gettext("Attendees settings") %>
</span>
<div class="flex space-x-2 items-center mt-3">
<ClaperWeb.Component.Input.check key={:chat_enabled} checked={@state.chat_enabled} />
<span><%= gettext("Enable messages") %></span>
<ClaperWeb.Component.Input.check
key={:chat_enabled}
checked={@state.chat_enabled}
shortcut={if @create == nil, do: "A", else: nil}
/>
<span><%= gettext("Enable messages") %><code class="pl-1">(A)</code></span>
</div>
<div class="flex space-x-2 items-center mt-3">
<ClaperWeb.Component.Input.check
key={:anonymous_chat_enabled}
checked={@state.anonymous_chat_enabled}
shortcut={if @create == nil, do: "S", else: nil}
/>
<span><%= gettext("Enable anonymous messages") %></span>
<span>
<%= gettext("Enable anonymous messages") %><code class="pl-1">(S)</code>
</span>
</div>
</div>
</div>

View File

@@ -65,10 +65,18 @@ defmodule ClaperWeb.EventLive.PollComponent do
</div>
<div class="flex space-x-3 z-10 text-left">
<%= if (length Enum.filter(@current_poll_vote, fn(vote) -> vote.poll_opt_id == opt.id end)) > 0 do %>
<span class="h-5 w-5 mt-0.5 rounded-full point-select bg-white"></span>
<%= if @poll.multiple do %>
<span class="h-5 w-5 mt-0.5 point-select bg-white"></span>
<% else %>
<span class="h-5 w-5 mt-0.5 rounded-full point-select bg-white"></span>
<% end %>
<% else %>
<span class="h-5 w-5 mt-0.5 rounded-full point-select border-2 border-white">
</span>
<%= if @poll.multiple do %>
<span class="h-5 w-5 mt-0.5 point-select border-2 border-white"></span>
<% else %>
<span class="h-5 w-5 mt-0.5 rounded-full point-select border-2 border-white">
</span>
<% end %>
<% end %>
<span class="flex-1"><%= opt.content %></span>
</div>
@@ -88,10 +96,18 @@ defmodule ClaperWeb.EventLive.PollComponent do
</div>
<div class="flex space-x-3 z-10 text-left">
<%= if Enum.member?(@selected_poll_opt, "#{idx}") do %>
<span class="h-5 w-5 mt-0.5 rounded-full point-select bg-white"></span>
<%= if @poll.multiple do %>
<span class="h-5 w-5 mt-0.5 point-select bg-white"></span>
<% else %>
<span class="h-5 w-5 mt-0.5 rounded-full point-select bg-white"></span>
<% end %>
<% else %>
<span class="h-5 w-5 mt-0.5 rounded-full point-select border-2 border-white">
</span>
<%= if @poll.multiple do %>
<span class="h-5 w-5 mt-0.5 point-select border-2 border-white"></span>
<% else %>
<span class="h-5 w-5 mt-0.5 rounded-full point-select border-2 border-white">
</span>
<% end %>
<% end %>
<span class="flex-1"><%= opt.content %></span>
</div>

View File

@@ -22,7 +22,7 @@ defmodule ClaperWeb.EventLive.PostComponent do
<img src="/images/icons/ellipsis-horizontal-white.svg" class="h-5" />
</button>
<%= if @post.name || is_a_leader(@post, @event, @leaders) do %>
<%= if @post.name || is_a_leader(@post, @event, @leaders) || is_pinned(@post) do %>
<div class="inline-flex items-center">
<%= if @post.name do %>
<p class="text-white text-xs font-semibold mb-2 mr-2"><%= @post.name %></p>
@@ -33,6 +33,32 @@ defmodule ClaperWeb.EventLive.PostComponent do
<span><%= gettext("Host") %></span>
</div>
<% end %>
<%= if is_pinned(@post) do %>
<div class="inline-flex items-center space-x-1 justify-center px-3 py-0.5 rounded-full text-xs font-medium bg-supporting-yellow-100 text-supporting-yellow-800 mb-2 ml-1">
<svg
xmlns="http://www.w3.org/2000/svg"
class="icon icon-tabler icon-tabler-pin-filled"
width="12"
height="12"
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path
d="M15.113 3.21l.094 .083l5.5 5.5a1 1 0 0 1 -1.175 1.59l-3.172 3.171l-1.424 3.797a1 1 0 0 1 -.158 .277l-.07 .08l-1.5 1.5a1 1 0 0 1 -1.32 .082l-.095 -.083l-2.793 -2.792l-3.793 3.792a1 1 0 0 1 -1.497 -1.32l.083 -.094l3.792 -3.793l-2.792 -2.793a1 1 0 0 1 -.083 -1.32l.083 -.094l1.5 -1.5a1 1 0 0 1 .258 -.187l.098 -.042l3.796 -1.425l3.171 -3.17a1 1 0 0 1 1.497 -1.26z"
stroke-width="0"
fill="currentColor"
>
</path>
</svg>
<span><%= gettext("Pinned") %></span>
</div>
<% end %>
</div>
<% end %>
@@ -124,6 +150,32 @@ defmodule ClaperWeb.EventLive.PostComponent do
</div>
<% end %>
<%= if is_pinned(@post) do %>
<div class="inline-flex items-center space-x-1 justify-center px-3 py-0.5 rounded-full text-xs font-medium bg-supporting-yellow-100 text-supporting-yellow-800 mb-2 ml-1">
<svg
xmlns="http://www.w3.org/2000/svg"
class="icon icon-tabler icon-tabler-pin-filled"
width="12"
height="12"
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path
d="M15.113 3.21l.094 .083l5.5 5.5a1 1 0 0 1 -1.175 1.59l-3.172 3.171l-1.424 3.797a1 1 0 0 1 -.158 .277l-.07 .08l-1.5 1.5a1 1 0 0 1 -1.32 .082l-.095 -.083l-2.793 -2.792l-3.793 3.792a1 1 0 0 1 -1.497 -1.32l.083 -.094l3.792 -3.793l-2.792 -2.793a1 1 0 0 1 -.083 -1.32l.083 -.094l1.5 -1.5a1 1 0 0 1 .258 -.187l.098 -.042l3.796 -1.425l3.171 -3.17a1 1 0 0 1 1.497 -1.26z"
stroke-width="0"
fill="currentColor"
>
</path>
</svg>
<span><%= gettext("Pinned") %></span>
</div>
<% end %>
<p><%= @post.body %></p>
<div class="flex h-6 text-xs float-right space-x-2">
@@ -218,4 +270,8 @@ defmodule ClaperWeb.EventLive.PostComponent do
leader.user_id == post.user_id
end))
end
defp is_pinned(post) do
post.pinned == true
end
end

View File

@@ -46,14 +46,23 @@ defmodule ClaperWeb.EventLive.Presenter do
|> assign(:event, event)
|> assign(:state, event.presentation_file.presentation_state)
|> assign(:posts, list_posts(socket, event.uuid))
|> assign(:pinned_posts, list_pinned_posts(socket, event.uuid))
|> assign(:show_only_pinned, event.presentation_file.presentation_state.show_only_pinned)
|> assign(:reacts, [])
|> poll_at_position
|> form_at_position
|> embed_at_position
{:ok, socket, temporary_assigns: [posts: []]}
{:ok, socket, temporary_assigns: []}
end
end
defp update_post_in_list(posts, updated_post) do
Enum.map(posts, fn post ->
if post.id == updated_post.id, do: updated_post, else: post
end)
end
defp is_leader(%{assigns: %{current_user: current_user}} = _socket, event) do
Claper.Events.is_leaded_by(current_user.email, event) || event.user.id == current_user.id
end
@@ -70,7 +79,23 @@ defmodule ClaperWeb.EventLive.Presenter do
def handle_info({:post_created, post}, socket) do
{:noreply,
socket
|> update(:posts, fn posts -> [post | posts] end)}
|> update(:posts, fn posts -> posts ++ [post] end)}
end
@impl true
def handle_info({:post_pinned, post}, socket) do
{:noreply,
socket
|> update(:pinned_posts, fn pinned_posts -> pinned_posts ++ [post] end)}
end
@impl true
def handle_info({:post_unpinned, post}, socket) do
{:noreply,
socket
|> update(:pinned_posts, fn pinned_posts ->
Enum.reject(pinned_posts, fn p -> p.id == post.id end)
end)}
end
@impl true
@@ -80,34 +105,41 @@ defmodule ClaperWeb.EventLive.Presenter do
|> assign(:state, state)
|> push_event("page", %{current_page: state.position})
|> push_event("reset-global-react", %{})
|> poll_at_position}
|> poll_at_position
|> embed_at_position}
end
@impl true
def handle_info({:post_updated, post}, socket) do
{:noreply, socket |> update(:posts, fn posts -> [post | posts] end)}
end
def handle_info({:post_updated, updated_post}, socket) do
updated_posts = update_post_in_list(socket.assigns.posts, updated_post)
updated_pinned_posts = update_post_in_list(socket.assigns.pinned_posts, updated_post)
@impl true
def handle_info({:reaction_added, post}, socket) do
{:noreply, socket |> update(:posts, fn posts -> [post | posts] end)}
end
@impl true
def handle_info({:reaction_removed, post}, socket) do
{:noreply, socket |> update(:posts, fn posts -> [post | posts] end)}
{:noreply,
socket
|> assign(:posts, updated_posts)
|> assign(:pinned_posts, updated_pinned_posts)}
end
@impl true
def handle_info({:post_deleted, post}, socket) do
{:noreply, socket |> update(:posts, fn posts -> [post | posts] end)}
updated_posts = Enum.reject(socket.assigns.posts, fn p -> p.id == post.id end)
updated_pinned_posts = Enum.reject(socket.assigns.pinned_posts, fn p -> p.id == post.id end)
{:noreply,
socket |> assign(:posts, updated_posts) |> assign(:pinned_posts, updated_pinned_posts)}
end
@impl true
def handle_info({:poll_updated, poll}, socket) do
{:noreply,
socket
|> update(:current_poll, fn _current_poll -> poll end)}
if poll.enabled do
{:noreply,
socket
|> update(:current_poll, fn _current_poll -> poll end)}
else
{:noreply,
socket
|> update(:current_poll, fn _current_poll -> nil end)}
end
end
@impl true
@@ -119,9 +151,15 @@ defmodule ClaperWeb.EventLive.Presenter do
@impl true
def handle_info({:form_updated, form}, socket) do
{:noreply,
socket
|> update(:current_form, fn _current_form -> form end)}
if form.active do
{:noreply,
socket
|> update(:current_form, fn _current_form -> form end)}
else
{:noreply,
socket
|> update(:current_form, fn _current_form -> nil end)}
end
end
@impl true
@@ -131,6 +169,26 @@ defmodule ClaperWeb.EventLive.Presenter do
|> update(:current_form, fn _current_form -> nil end)}
end
@impl true
def handle_info({:embed_updated, embed}, socket) do
if embed.active do
{:noreply,
socket
|> update(:current_embed, fn _current_embed -> embed end)}
else
{:noreply,
socket
|> update(:current_embed, fn _current_embed -> nil end)}
end
end
@impl true
def handle_info({:embed_deleted, _embed}, socket) do
{:noreply,
socket
|> update(:current_embed, fn _current_embed -> nil end)}
end
@impl true
def handle_info({:chat_visible, value}, socket) do
{:noreply,
@@ -139,6 +197,14 @@ defmodule ClaperWeb.EventLive.Presenter do
|> update(:chat_visible, fn _chat_visible -> value end)}
end
@impl true
def handle_info({:show_only_pinned, value}, socket) do
{:noreply,
socket
|> push_event("show_only_pinned", %{value: value})
|> update(:show_only_pinned, fn _show_only_pinned -> value end)}
end
@impl true
def handle_info({:poll_visible, value}, socket) do
{:noreply,
@@ -178,6 +244,14 @@ defmodule ClaperWeb.EventLive.Presenter do
{:noreply, socket |> assign(:current_form, form)}
end
@impl true
def handle_info(
{:current_embed, embed},
socket
) do
{:noreply, socket |> assign(:current_embed, embed)}
end
@impl true
def handle_info(_, socket) do
{:noreply, socket}
@@ -212,7 +286,21 @@ defmodule ClaperWeb.EventLive.Presenter do
end
end
defp embed_at_position(%{assigns: %{event: event, state: state}} = socket) do
with embed <-
Claper.Embeds.get_embed_current_position(
event.presentation_file.id,
state.position
) do
socket |> assign(:current_embed, embed)
end
end
defp list_posts(_socket, event_id) do
Claper.Posts.list_posts(event_id, [:event, :reactions])
end
defp list_pinned_posts(_socket, event_id) do
Claper.Posts.list_pinned_posts(event_id, [:event, :reactions])
end
end

View File

@@ -1,7 +1,12 @@
<style>
body {
background: black;
}
background: black;
}
iframe {
width: 100%;
height: 100%;
}
</style>
<div
@@ -14,7 +19,7 @@
<!-- JOIN SCREEN -->
<div
id="joinScreen"
class={"#{if @state.join_screen_visible, do: 'opacity-100', else: 'opacity-0'} h-full w-full flex flex-col justify-center bg-black absolute z-30 transition-opacity"}
class={"#{if @state.join_screen_visible, do: 'opacity-100 z-40', else: 'opacity-0'} h-full w-full flex flex-col justify-center bg-black absolute transition-opacity"}
>
<div class="h-full bg-black text-white bg-opacity-50 text-center flex flex-col items-center justify-center">
<span class="font-semibold mb-10 sm:text-3xl md:text-4xl lg:text-6xl">
@@ -68,6 +73,15 @@
</div>
</div>
<% end %>
<%= if @current_embed do %>
<!-- EMBED -->
<div
id="embed"
class={"#{if @state.chat_visible, do: 'h-5/6 w-9/12 right-0', else: 'h-screen w-full'} transition-all duration-150 inline-block transform -translate-y-1/2 top-1/2 z-30 absolute transition-opacity"}
>
<%= raw(@current_embed.content) %>
</div>
<% end %>
<!-- MESSAGES -->
<div
id="slider-wrapper"
@@ -75,40 +89,80 @@
>
<div
class={"#{if @state.chat_visible, do: 'opacity-100 w-3/12 px-4 showed', else: 'opacity-0 w-0 p-0'} transition-all duration-150 flex flex-col h-screen py-5 justify-end max-h-screen bg-black"}
id="post-list"
phx-update="append"
id="post-list-wrapper"
phx-update="replace"
>
<%= for post <- @posts do %>
<div class={if post.__meta__.state == :deleted, do: "hidden"} id={"#{post.id}-post"}>
<div class="px-4 pb-2 pt-3 rounded-b-lg rounded-tr-lg bg-white shadow-md text-black break-word mt-4">
<%= if post.name do %>
<p class="text-gray-400 text-lg font-semibold mb-2 mr-2"><%= post.name %></p>
<% end %>
<p class="text-3xl"><%= post.body %></p>
<%= if @state.show_only_pinned == false do %>
<div id="post-list" phx-update="replace">
<%= for post <- @posts do %>
<div class={if post.__meta__.state == :deleted, do: "hidden"} id={"#{post.id}-post"}>
<div class="px-4 pb-2 pt-3 rounded-b-lg rounded-tr-lg bg-white shadow-md text-black break-word mt-4">
<%= if post.name do %>
<p class="text-gray-400 text-lg font-semibold mb-2 mr-2"><%= post.name %></p>
<% end %>
<p class="text-3xl"><%= post.body %></p>
<%= if post.like_count > 0 || post.love_count > 0 || post.lol_count > 0 do %>
<div class="flex h-6 space-x-2 text-lg text-gray-500 pb-3 items-center mt-5">
<div class="flex items-center">
<%= if post.like_count > 0 do %>
<img src="/images/icons/thumb.svg" class="h-7" />
<span class="ml-1"><%= post.like_count %></span>
<% end %>
</div>
<div class="flex items-center">
<%= if post.love_count > 0 do %>
<img src="/images/icons/heart.svg" class="h-7" />
<span class="ml-1"><%= post.love_count %></span>
<% end %>
</div>
<div class="flex items-center">
<%= if post.lol_count > 0 do %>
<img src="/images/icons/laugh.svg" class="h-7" />
<span class="ml-1"><%= post.lol_count %></span>
<% end %>
</div>
<%= if post.like_count > 0 || post.love_count > 0 || post.lol_count > 0 do %>
<div class="flex h-6 space-x-2 text-lg text-gray-500 pb-3 items-center mt-5">
<div class="flex items-center">
<%= if post.like_count > 0 do %>
<img src="/images/icons/thumb.svg" class="h-7" />
<span class="ml-1"><%= post.like_count %></span>
<% end %>
</div>
<div class="flex items-center">
<%= if post.love_count > 0 do %>
<img src="/images/icons/heart.svg" class="h-7" />
<span class="ml-1"><%= post.love_count %></span>
<% end %>
</div>
<div class="flex items-center">
<%= if post.lol_count > 0 do %>
<img src="/images/icons/laugh.svg" class="h-7" />
<span class="ml-1"><%= post.lol_count %></span>
<% end %>
</div>
</div>
<% end %>
</div>
<% end %>
</div>
</div>
<% end %>
</div>
<% else %>
<div id="pinned-posts" phx-update="replace">
<%= for post <- @pinned_posts do %>
<div class={if post.__meta__.state == :deleted, do: "hidden"} id={"#{post.id}-post"}>
<div class="px-4 pb-2 pt-3 rounded-b-lg rounded-tr-lg bg-white shadow-md text-black break-word mt-4">
<%= if post.name do %>
<p class="text-gray-400 text-lg font-semibold mb-2 mr-2"><%= post.name %></p>
<% end %>
<p class="text-3xl"><%= post.body %></p>
<%= if post.like_count > 0 || post.love_count > 0 || post.lol_count > 0 do %>
<div class="flex h-6 space-x-2 text-lg text-gray-500 pb-3 items-center mt-5">
<div class="flex items-center">
<%= if post.like_count > 0 do %>
<img src="/images/icons/thumb.svg" class="h-7" />
<span class="ml-1"><%= post.like_count %></span>
<% end %>
</div>
<div class="flex items-center">
<%= if post.love_count > 0 do %>
<img src="/images/icons/heart.svg" class="h-7" />
<span class="ml-1"><%= post.love_count %></span>
<% end %>
</div>
<div class="flex items-center">
<%= if post.lol_count > 0 do %>
<img src="/images/icons/laugh.svg" class="h-7" />
<span class="ml-1"><%= post.lol_count %></span>
<% end %>
</div>
</div>
<% end %>
</div>
</div>
<% end %>
</div>
<% end %>
</div>

View File

@@ -1,7 +1,7 @@
defmodule ClaperWeb.EventLive.Show do
use ClaperWeb, :live_view
alias Claper.{Posts, Polls, Forms}
alias Claper.{Posts, Polls, Forms, Embeds}
alias ClaperWeb.Presence
on_mount(ClaperWeb.AttendeeLiveAuth)
@@ -86,6 +86,7 @@ defmodule ClaperWeb.EventLive.Show do
|> starting_soon_assigns(event)
|> get_current_poll(event)
|> get_current_form(event)
|> get_current_embed(event)
|> check_leader(event)
|> leader_list(event)
@@ -245,11 +246,29 @@ defmodule ClaperWeb.EventLive.Show do
end
end
@impl true
def handle_info(
{:current_embed, embed},
socket
) do
{:noreply, socket |> assign(:current_embed, embed)}
end
@impl true
def handle_info({:post_updated, post}, socket) do
{:noreply, socket |> update(:posts, fn posts -> [post | posts] end)}
end
@impl true
def handle_info({:post_pinned, post}, socket) do
{:noreply, socket |> update(:posts, fn posts -> [post | posts] end)}
end
@impl true
def handle_info({:post_unpinned, post}, socket) do
{:noreply, socket |> update(:posts, fn posts -> [post | posts] end)}
end
@impl true
def handle_info({:reaction_added, post}, socket) do
{:noreply, socket |> update(:posts, fn posts -> [post | posts] end)}
@@ -267,9 +286,15 @@ defmodule ClaperWeb.EventLive.Show do
@impl true
def handle_info({:poll_updated, poll}, socket) do
{:noreply,
socket
|> update(:current_poll, fn _current_poll -> poll end)}
if poll.enabled do
{:noreply,
socket
|> update(:current_poll, fn _current_poll -> poll end)}
else
{:noreply,
socket
|> update(:current_poll, fn _current_poll -> nil end)}
end
end
@impl true
@@ -281,9 +306,15 @@ defmodule ClaperWeb.EventLive.Show do
@impl true
def handle_info({:form_updated, form}, socket) do
{:noreply,
socket
|> update(:current_form, fn _current_form -> form end)}
if form.enabled do
{:noreply,
socket
|> update(:current_form, fn _current_form -> form end)}
else
{:noreply,
socket
|> update(:current_form, fn _current_form -> nil end)}
end
end
@impl true
@@ -293,6 +324,26 @@ defmodule ClaperWeb.EventLive.Show do
|> update(:current_form, fn _current_form -> nil end)}
end
@impl true
def handle_info({:embed_updated, embed}, socket) do
if embed.enabled do
{:noreply,
socket
|> update(:current_embed, fn _current_embed -> embed end)}
else
{:noreply,
socket
|> update(:current_embed, fn _current_embed -> nil end)}
end
end
@impl true
def handle_info({:embed_deleted, _embed}, socket) do
{:noreply,
socket
|> update(:current_embed, fn _current_embed -> nil end)}
end
@impl true
def handle_info({:react, type}, socket) do
{:noreply,
@@ -647,6 +698,16 @@ defmodule ClaperWeb.EventLive.Show do
end
end
defp get_current_embed(socket, event) do
with embed <-
Embeds.get_embed_current_position(
event.presentation_file.id,
event.presentation_file.presentation_state.position
) do
socket |> assign(:current_embed, embed)
end
end
defp get_current_vote(%{assigns: %{current_user: current_user}} = socket, poll_id)
when is_map(current_user) do
vote = Polls.get_poll_vote(current_user.id, poll_id)

View File

@@ -88,6 +88,24 @@
</div>
<% end %>
<%= if @current_embed != nil and @current_embed.attendee_visibility == true do %>
<div
id="embed-wrapper-parent"
class="animate__animated animate__zoomInDown w-full lg:w-1/3 lg:mx-auto fixed top-16 z-10 px-2 pb-6 lg:px-7 max-h-screen overflow-y-auto"
>
<div class="transition-all" id="embed-wrapper">
<.live_component
module={ClaperWeb.EventLive.EmbedComponent}
id={"#{@current_embed.id}-embed"}
embed={@current_embed}
current_user={@current_user}
attendee_identifier={@attendee_identifier}
event={@event}
/>
</div>
</div>
<% end %>
<div
class="flex flex-col space-y-4 px-5 pt-20 pb-32 lg:w-1/3 bg-black min-h-screen"
id="post-list"

View File

@@ -13,7 +13,7 @@ defmodule ClaperWeb.StatLive.Index do
event =
Events.get_managed_event!(socket.assigns.current_user, id,
presentation_file: [polls: [:poll_opts], forms: [:form_submits]]
presentation_file: [polls: [:poll_opts], forms: [:form_submits], embeds: []]
)
grouped_total_votes = Claper.Stats.total_vote_count(event.presentation_file.id)

View File

@@ -252,6 +252,17 @@
<% end %>
<% end %>
<%= for embed <- Enum.filter(@event.presentation_file.embeds , fn e -> e.position == position end) do %>
<span class="text-2xl font-semibold text-gray-900 mb-4">
<%= gettext("Web content") %>: <%= embed.title %>
</span>
<div class="px-4 pb-2 pt-3 rounded-b-lg rounded-tr-lg bg-white relative shadow-md text-black break-all mt-4">
<div class="flex space-x-3 items-center">
<%= raw(embed.content) %>
</div>
</div>
<% end %>
<% posts = Enum.filter(@posts, fn p -> p.position == position end) %>
<span class="text-2xl font-semibold text-gray-900 mb-4">Messages</span>

View File

@@ -0,0 +1,15 @@
defmodule ClaperWeb.Notifiers.LeaderNotifier do
use Phoenix.Swoosh, view: ClaperWeb.LeaderNotifierView, layout: {ClaperWeb.LayoutView, :email}
import ClaperWeb.Gettext
def event_invitation(event_name, email, url) do
new()
|> to(email)
|> from(
{Application.get_env(:claper, :mail) |> Keyword.get(:from_name),
Application.get_env(:claper, :mail) |> Keyword.get(:from)}
)
|> subject(gettext("You have been invited to manage an event"))
|> render_body("invitation.html", %{event_name: event_name, leader_email: email, url: url})
end
end

View File

@@ -68,6 +68,8 @@ defmodule ClaperWeb.Router do
live("/e/:code/manage/add/form", EventLive.Manage, :add_form)
live("/e/:code/manage/import", EventLive.Manage, :import)
live("/e/:code/manage/edit/form/:id", EventLive.Manage, :edit_form)
live("/e/:code/manage/add/embed", EventLive.Manage, :add_embed)
live("/e/:code/manage/edit/embed/:id", EventLive.Manage, :edit_embed)
end
end
@@ -112,6 +114,7 @@ defmodule ClaperWeb.Router do
get("/users/reset_password", UserResetPasswordController, :new)
post("/users/reset_password", UserResetPasswordController, :create)
get("/users/reset_password/:token", UserResetPasswordController, :edit)
post("/users/reset_password/:token", UserResetPasswordController, :update)
end
scope "/", ClaperWeb do

View File

@@ -0,0 +1,60 @@
<tr>
<td>
<table
width="95%"
border="0"
align="center"
cellpadding="0"
cellspacing="0"
style="max-width:670px;background:#fff; border-radius:3px; text-align:center;-webkit-box-shadow:0 6px 18px 0 rgba(0,0,0,.06);-moz-box-shadow:0 6px 18px 0 rgba(0,0,0,.06);box-shadow:0 6px 18px 0 rgba(0,0,0,.06);"
>
<tr>
<td style="height:40px;">&nbsp;</td>
</tr>
<tr>
<td style="padding:0 35px;">
<h1 style="color:#1e1e2d; font-weight:500; margin:0;font-size:32px;font-family:'Rubik',sans-serif;">
<%= gettext("You have been invited") %>
</h1>
<span style="display:inline-block; vertical-align:middle; margin:29px 0 26px; border-bottom:1px solid #cecece; width:100px;">
</span>
<p style="color:#455056; font-size:15px;line-height:24px; margin:0;">
<%= gettext("Someone invited you to manage the event: %{name}", name: @event_name) %>
</p>
<p style="color:#455056; font-size:15px;line-height:24px; margin:0;">
<%= gettext(
"To accept the invitation, please login or create an account with this email: %{email}",
email: @leader_email
) %>
</p>
<a
href={@url}
target="_blank"
style="background:#8611ed;text-decoration:none !important; font-weight:500; margin-top:35px; color:#fff;text-transform:uppercase; font-size:14px;padding:10px 24px;display:inline-block;border-radius:50px;"
>
<%= gettext("Login or create account") %>
</a>
</td>
</tr>
<tr>
<td style="height:20px;">&nbsp;</td>
</tr>
<tr>
<td style="font-size: 0.8em; color: #6C6C6C">
<p class="sub">
<%= gettext(
"If youre having trouble with the button above, copy and paste the URL below into your web browser"
) %>.
</p>
<p class="sub"><%= @url %></p>
</td>
</tr>
<tr>
<td style="height:40px;">&nbsp;</td>
</tr>
</table>
</td>
</tr>
<tr>
<td style="height:20px;">&nbsp;</td>
</tr>

View File

@@ -0,0 +1,58 @@
<div>
<div class="relative min-h-screen bg-black">
<div class="flex justify-center md:items-center h-screen w-full p-8 md:p-10 lg:p-14 sm:rounded-lg md:rounded-none ">
<div class="max-w-xl w-full space-y-4 mx-auto">
<div class="text-center">
<h2 class="mt-6 font-bold text-gray-100">
<a href="/">
<img src="/images/logo.svg" class="h-10 w-auto inline" />
</a>
</h2>
<h2 class="mt-6 text-3xl font-bold text-gray-100">
<%= gettext("Reset your password") %>
</h2>
</div>
<.form
:let={f}
for={@changeset}
action={Routes.user_reset_password_path(@conn, :update, @token)}
method="post"
class="mt-8 space-y-6"
>
<%= if @changeset.action do %>
<ClaperWeb.Component.Alert.error
message={gettext("Oops, check that all fields are filled in correctly.")}
stick={true}
/>
<% end %>
<ClaperWeb.Component.Input.password
form={f}
key={:password}
labelClass="text-white"
fieldClass="bg-gray-700 text-white"
name={gettext("Password")}
required="true"
/>
<ClaperWeb.Component.Input.password
form={f}
key={:password_confirmation}
labelClass="text-white"
fieldClass="bg-gray-700 text-white"
name={gettext("Password confirmation")}
required="true"
/>
<div>
<button
type="submit"
class="w-full flex justify-center text-white p-4 rounded-full tracking-wide font-bold focus:outline-none focus:shadow-outline shadow-lg bg-gradient-to-tl from-primary-500 to-secondary-500 bg-size-200 bg-pos-0 hover:bg-pos-100 transition-all duration-500"
>
<%= gettext("Confirm new password") %>
</button>
</div>
</.form>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,48 @@
<div>
<div class="relative min-h-screen bg-black">
<div class="flex justify-center md:items-center h-screen w-full p-8 md:p-10 lg:p-14 sm:rounded-lg md:rounded-none ">
<div class="max-w-xl w-full space-y-4 mx-auto">
<div class="text-center">
<h2 class="mt-6 font-bold text-gray-100">
<a href="/">
<img src="/images/logo.svg" class="h-10 w-auto inline" />
</a>
</h2>
<h2 class="mt-6 text-3xl font-bold text-gray-100">
<%= gettext("Reset your password") %>
</h2>
</div>
<.form
:let={f}
for={@changeset}
action={Routes.user_reset_password_path(@conn, :create)}
class="mt-8 space-y-6"
>
<%= if @changeset.action do %>
<ClaperWeb.Component.Alert.error
message={gettext("Oops, check that all fields are filled in correctly.")}
stick={true}
/>
<% end %>
<ClaperWeb.Component.Input.email
form={f}
key={:email}
labelClass="text-white"
fieldClass="bg-gray-700 text-white"
name={gettext("Email")}
required="true"
/>
<div>
<button
type="submit"
class="w-full flex justify-center text-white p-4 rounded-full tracking-wide font-bold focus:outline-none focus:shadow-outline shadow-lg bg-gradient-to-tl from-primary-500 to-secondary-500 bg-size-200 bg-pos-0 hover:bg-pos-100 transition-all duration-500"
>
<%= gettext("Send link to reset password") %>
</button>
</div>
</.form>
</div>
</div>
</div>
</div>

View File

@@ -68,7 +68,11 @@
</div>
</.form>
<div class="mt-4 text-center">
<div class="mt-4 text-center flex gap-x-2 justify-center">
<%= link(gettext("Forgot your password?"),
to: Routes.user_reset_password_path(@conn, :new),
class: "text-white text-sm text-center"
) %>
<%= if Application.get_env(:claper, :enable_account_creation) do %>
<%= link(gettext("Create account"),
to: Routes.user_registration_path(@conn, :new),

View File

@@ -37,6 +37,39 @@ defmodule ClaperWeb.Component.Input do
"""
end
def textarea(assigns) do
assigns =
assigns
|> assign_new(:required, fn -> false end)
|> assign_new(:autofocus, fn -> false end)
|> assign_new(:placeholder, fn -> false end)
|> assign_new(:readonly, fn -> false end)
|> assign_new(:labelClass, fn -> "text-gray-700" end)
|> assign_new(:fieldClass, fn -> "bg-white" end)
|> assign_new(:value, fn -> input_value(assigns.form, assigns.key) end)
~H"""
<div class="relative">
<%= label(@form, @key, @name, class: "block text-sm font-medium #{@labelClass}") %>
<div class="mt-1">
<%= text_input(@form, @key,
required: @required,
readonly: @readonly,
autofocus: @autofocus,
placeholder: @placeholder,
autocomplete: @key,
value: @value,
class:
"#{@fieldClass} read-only:opacity-50 outline-none shadow-base focus:ring-primary-500 focus:border-primary-500 focus:ring-2 block w-full text-lg border-gray-300 rounded-md py-4 px-3"
) %>
</div>
<%= if Keyword.has_key?(@form.errors, @key) do %>
<p class="text-supporting-red-500 text-sm"><%= error_tag(@form, @key) %></p>
<% end %>
</div>
"""
end
def select(assigns) do
assigns =
assigns
@@ -70,6 +103,7 @@ defmodule ClaperWeb.Component.Input do
assigns =
assigns
|> assign_new(:disabled, fn -> false end)
|> assign_new(:shortcut, fn -> nil end)
~H"""
<!-- Enabled: "bg-indigo-600", Not Enabled: "bg-gray-200" -->
@@ -82,6 +116,8 @@ defmodule ClaperWeb.Component.Input do
class={"#{if @checked, do: 'bg-primary-600', else: 'bg-gray-200'} relative inline-flex flex-shrink-0 h-8 w-14 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200"}
role="switch"
aria-checked="false"
phx-key={@shortcut}
phx-window-keydown={if @shortcut && not @disabled, do: checked(@checked, @key)}
>
<!-- Enabled: "translate-x-5", Not Enabled: "translate-x-0" -->
<span class={"#{if @checked, do: 'translate-x-6', else: 'translate-x-0'} pointer-events-none relative inline-block h-7 w-7 rounded-full bg-white shadow transform ring-0 transition ease-in-out duration-200"}>

View File

@@ -0,0 +1,5 @@
defmodule ClaperWeb.LeaderNotifierView do
use Phoenix.View, root: "lib/claper_web/templates"
import ClaperWeb.Gettext
use Phoenix.HTML
end

View File

@@ -1,3 +1,4 @@
defmodule ClaperWeb.UserResetPasswordView do
import Phoenix.Component
use ClaperWeb, :view
end

View File

@@ -1,7 +1,7 @@
defmodule Claper.MixProject do
use Mix.Project
@version "1.6.0"
@version "1.7.0"
def project do
[
@@ -16,7 +16,7 @@ defmodule Claper.MixProject do
# Docs
name: "Claper",
source_url: "https://github.com/ClaperCo/Claper",
homepage_url: "https://get.claper.co",
homepage_url: "https://claper.co",
docs: [
main: "overview",
assets: "guides/assets",
@@ -102,8 +102,8 @@ defmodule Claper.MixProject do
{:phoenix_live_dashboard, "~> 0.7"},
{:esbuild, "~> 0.2", runtime: Mix.env() == :dev},
{:dart_sass, "~> 0.5", runtime: Mix.env() == :dev},
{:swoosh, "~> 1.3"},
{:finch, "~> 0.8"},
{:swoosh, "~> 1.12"},
{:finch, "~> 0.16"},
{:telemetry_metrics, "~> 0.6"},
{:telemetry_poller, "~> 1.0"},
{:gettext, "~> 0.18"},

View File

@@ -1,24 +1,24 @@
%{
"bcrypt_elixir": {:hex, :bcrypt_elixir, "2.3.1", "5114d780459a04f2b4aeef52307de23de961b69e13a5cd98a911e39fda13f420", [:make, :mix], [{:comeonin, "~> 5.3", [hex: :comeonin, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.6", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "42182d5f46764def15bf9af83739e3bf4ad22661b1c34fc3e88558efced07279"},
"bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"},
"castore": {:hex, :castore, "1.0.1", "240b9edb4e9e94f8f56ab39d8d2d0a57f49e46c56aced8f873892df8ff64ff5a", [:mix], [], "hexpm", "b4951de93c224d44fac71614beabd88b71932d0b1dea80d2f80fb9044e01bbb3"},
"certifi": {:hex, :certifi, "2.9.0", "6f2a475689dd47f19fb74334859d460a2dc4e3252a3324bd2111b8f0429e7e21", [:rebar3], [], "hexpm", "266da46bdb06d6c6d35fde799bcb28d36d985d424ad7c08b5bb48f5b5cdd4641"},
"castore": {:hex, :castore, "1.0.4", "ff4d0fb2e6411c0479b1d965a814ea6d00e51eb2f58697446e9c41a97d940b28", [:mix], [], "hexpm", "9418c1b8144e11656f0be99943db4caf04612e3eaecefb5dae9a2a87565584f8"},
"certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"},
"comeonin": {:hex, :comeonin, "5.3.3", "2c564dac95a35650e9b6acfe6d2952083d8a08e4a89b93a481acb552b325892e", [:mix], [], "hexpm", "3e38c9c2cb080828116597ca8807bb482618a315bfafd98c90bc22a821cc84df"},
"connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"},
"cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"},
"cowboy": {:hex, :cowboy, "2.10.0", "ff9ffeff91dae4ae270dd975642997afe2a1179d94b1887863e43f681a203e26", [:make, :rebar3], [{:cowlib, "2.12.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "3afdccb7183cc6f143cb14d3cf51fa00e53db9ec80cdcd525482f5e99bc41d6b"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
"cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
"cowlib": {:hex, :cowlib, "2.12.1", "a9fa9a625f1d2025fe6b462cb865881329b5caff8f1854d1cbc9f9533f00e1e1", [:make, :rebar3], [], "hexpm", "163b73f6367a7341b33c794c4e88e7dbfe6498ac42dcd69ef44c5bc5507c8db0"},
"credo": {:hex, :credo, "1.7.0", "6119bee47272e85995598ee04f2ebbed3e947678dee048d10b5feca139435f75", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "6839fcf63d1f0d1c0f450abc8564a57c43d644077ab96f2934563e68b8a769d7"},
"csv": {:hex, :csv, "3.0.5", "3c1455127e92de8845806db89554ad7d45e0212974be41dd9c38a5c881861713", [:mix], [], "hexpm", "cbbe5455c93df5f3f2943e995e28b7a8808361ba34cf3e44267d77a01eaf1609"},
"dart_sass": {:hex, :dart_sass, "0.6.0", "1fe560c3ed5c577b6b9cf97134a0e05c82b69645d313b1ef0ffb4d659c3d0300", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "41f7bb065b5c30c3ea05e8b41aa3f9b5c62817079b94f70e2a22d133828475bb"},
"db_connection": {:hex, :db_connection, "2.5.0", "bb6d4f30d35ded97b29fe80d8bd6f928a1912ca1ff110831edcd238a1973652c", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c92d5ba26cd69ead1ff7582dbb860adeedfff39774105a4f1c92cbb654b55aa2"},
"decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"},
"earmark_parser": {:hex, :earmark_parser, "1.4.31", "a93921cdc6b9b869f519213d5bc79d9e218ba768d7270d46fdcf1c01bacff9e2", [:mix], [], "hexpm", "317d367ee0335ef037a87e46c91a2269fef6306413f731e8ec11fc45a7efd059"},
"ecto": {:hex, :ecto, "3.10.1", "c6757101880e90acc6125b095853176a02da8f1afe056f91f1f90b80c9389822", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "d2ac4255f1601bdf7ac74c0ed971102c6829dc158719b94bd30041bbad77f87a"},
"ecto_sql": {:hex, :ecto_sql, "3.10.1", "6ea6b3036a0b0ca94c2a02613fd9f742614b5cfe494c41af2e6571bb034dd94c", [:mix], [{:db_connection, "~> 2.5 or ~> 2.4.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.10.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 0.17.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f6a25bdbbd695f12c8171eaff0851fa4c8e72eec1e98c7364402dda9ce11c56b"},
"elixir_make": {:hex, :elixir_make, "0.7.6", "67716309dc5d43e16b5abbd00c01b8df6a0c2ab54a8f595468035a50189f9169", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "5a0569756b0f7873a77687800c164cca6dfc03a09418e6fcf853d78991f49940"},
"esbuild": {:hex, :esbuild, "0.7.0", "ce3afb13cd2c5fd63e13c0e2d0e0831487a97a7696cfa563707342bb825d122a", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "4ae9f4f237c5ebcb001390b8ada65a12fb2bb04f3fe3d1f1692b7a06fbfe8752"},
"ex_aws": {:hex, :ex_aws, "2.4.2", "d2686c34b69287cc8dd7629e70131aec05fef3cd3eae13698c9422933f7bc9ee", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8 or ~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:mime, "~> 1.2 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "0a2c07bd1541b0bef315f67e050d3cb9f947ab1a281896a8c35e3ee4976889f6"},
"ex_aws": {:hex, :ex_aws, "2.5.0", "1785e69350b16514c1049330537c7da10039b1a53e1d253bbd703b135174aec3", [:mix], [{:configparser_ex, "~> 4.0", [hex: :configparser_ex, repo: "hexpm", optional: true]}, {:hackney, "~> 1.16", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: true]}, {:jsx, "~> 2.8 or ~> 3.0", [hex: :jsx, repo: "hexpm", optional: true]}, {:mime, "~> 1.2 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:sweet_xml, "~> 0.7", [hex: :sweet_xml, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "971b86e5495fc0ae1c318e35e23f389e74cf322f2c02d34037c6fc6d405006f1"},
"ex_aws_s3": {:hex, :ex_aws_s3, "2.4.0", "ce8decb6b523381812798396bc0e3aaa62282e1b40520125d1f4eff4abdff0f4", [:mix], [{:ex_aws, "~> 2.0", [hex: :ex_aws, repo: "hexpm", optional: false]}, {:sweet_xml, ">= 0.0.0", [hex: :sweet_xml, repo: "hexpm", optional: true]}], "hexpm", "85dda6e27754d94582869d39cba3241d9ea60b6aa4167f9c88e309dc687e56bb"},
"ex_doc": {:hex, :ex_doc, "0.29.4", "6257ecbb20c7396b1fe5accd55b7b0d23f44b6aa18017b415cb4c2b91d997729", [:mix], [{:earmark_parser, "~> 1.4.31", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "2c6699a737ae46cb61e4ed012af931b57b699643b24dabe2400a8168414bc4f5"},
"expo": {:hex, :expo, "0.4.1", "1c61d18a5df197dfda38861673d392e642649a9cef7694d2f97a587b2cfb319b", [:mix], [], "hexpm", "2ff7ba7a798c8c543c12550fa0e2cbc81b95d4974c65855d8d15ba7b37a1ce47"},
@@ -27,26 +27,26 @@
"floki": {:hex, :floki, "0.34.2", "5fad07ef153b3b8ec110b6b155ec3780c4b2c4906297d0b4be1a7162d04a7e02", [:mix], [], "hexpm", "26b9d50f0f01796bc6be611ca815c5e0de034d2128e39cc9702eee6b66a4d1c8"},
"gen_smtp": {:hex, :gen_smtp, "1.2.0", "9cfc75c72a8821588b9b9fe947ae5ab2aed95a052b81237e0928633a13276fd3", [:rebar3], [{:ranch, ">= 1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "5ee0375680bca8f20c4d85f58c2894441443a743355430ff33a783fe03296779"},
"gettext": {:hex, :gettext, "0.22.3", "c8273e78db4a0bb6fba7e9f0fd881112f349a3117f7f7c598fa18c66c888e524", [:mix], [{:expo, "~> 0.4.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "935f23447713954a6866f1bb28c3a878c4c011e802bcd68a726f5e558e4b64bd"},
"hackney": {:hex, :hackney, "1.18.1", "f48bf88f521f2a229fc7bae88cf4f85adc9cd9bcf23b5dc8eb6a1788c662c4f6", [:rebar3], [{:certifi, "~>2.9.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.3.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "a4ecdaff44297e9b5894ae499e9a070ea1888c84afdd1fd9b7b2bc384950128e"},
"hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~>2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~>6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~>1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~>1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~>1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"},
"hashids": {:hex, :hashids, "2.1.0", "aabbcc4f9fa0b460cc6ef629f5bcbc35e7e87b382fee79f9c50be40b86574288", [:mix], [], "hexpm", "172163b1642d415881ef1c6e1f1be12d4e92b0711d5bbbd8854f82a1ce32d60b"},
"honeybadger": {:hex, :honeybadger, "0.18.1", "f61f71147d9e6ce8cdc6114e5df5eed4d2daa32dd15308267a1dacf5fa88b1e9", [:mix], [{:ecto, ">= 2.0.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:hackney, "~> 1.1", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:phoenix, ">= 1.0.0 and < 2.0.0", [hex: :phoenix, repo: "hexpm", optional: true]}, {:plug, ">= 1.0.0 and < 2.0.0", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "693e14b1b7d254dd75f977240c208d6b69cc1cbdd515bdd5b8b1738a1baf5fd5"},
"hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"},
"html_entities": {:hex, :html_entities, "0.5.2", "9e47e70598da7de2a9ff6af8758399251db6dbb7eebe2b013f2bbd2515895c3c", [:mix], [], "hexpm", "c53ba390403485615623b9531e97696f076ed415e8d8058b1dbaa28181f4fdcc"},
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~>0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"},
"jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"},
"jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"},
"libcluster": {:hex, :libcluster, "3.3.2", "84c6ebfdc72a03805955abfb5ff573f71921a3e299279cc3445445d5af619ad1", [:mix], [{:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "8b691ce8185670fc8f3fc0b7ed59eff66c6889df890d13411f8f1a0e6871d8a5"},
"makeup": {:hex, :makeup, "1.1.0", "6b67c8bc2882a6b6a445859952a602afc1a41c2e08379ca057c0f525366fc3ca", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "0a45ed501f4a8897f580eabf99a2e5234ea3e75a4373c8a52824f6e873be57a6"},
"makeup_elixir": {:hex, :makeup_elixir, "0.16.1", "cc9e3ca312f1cfeccc572b37a09980287e243648108384b97ff2b76e505c3555", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "e127a341ad1b209bd80f7bd1620a15693a9908ed780c3b763bccf7d200c767c6"},
"makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"},
"mime": {:hex, :mime, "2.0.3", "3676436d3d1f7b81b5a2d2bd8405f412c677558c81b1c92be58c00562bb59095", [:mix], [], "hexpm", "27a30bf0db44d25eecba73755acf4068cbfe26a4372f9eb3e4ea3a45956bff6b"},
"mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"},
"mimerl": {:hex, :mimerl, "1.2.0", "67e2d3f571088d5cfd3e550c383094b47159f3eee8ffa08e64106cdf5e981be3", [:rebar3], [], "hexpm", "f278585650aa581986264638ebf698f8bb19df297f66ad91b18910dfc6e19323"},
"mint": {:hex, :mint, "1.5.1", "8db5239e56738552d85af398798c80648db0e90f343c8469f6c6d8898944fb6f", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "4a63e1e76a7c3956abd2c72f370a0d0aecddc3976dea5c27eccbecfa5e7d5b1e"},
"mogrify": {:hex, :mogrify, "0.9.2", "b360984adea7dd6a55f18028e6327973c58de7f548fdb86c9859848aa904d5b0", [:mix], [], "hexpm", "c18d10fd70ca20e2585301616c89f6e4f7159d92efc9cc8ee579e00c886f699d"},
"nimble_options": {:hex, :nimble_options, "1.0.1", "b448018287b22584e91b5fd9c6c0ad717cb4bcdaa457957c8d57770f56625c43", [:mix], [], "hexpm", "078b2927cd9f84555be6386d56e849b0c555025ecccf7afee00ab6a9e6f63837"},
"nimble_options": {:hex, :nimble_options, "1.0.2", "92098a74df0072ff37d0c12ace58574d26880e522c22801437151a159392270e", [:mix], [], "hexpm", "fd12a8db2021036ce12a309f26f564ec367373265b53e25403f0ee697380f1b8"},
"nimble_parsec": {:hex, :nimble_parsec, "1.3.0", "9e18a119d9efc3370a3ef2a937bf0b24c088d9c4bf0ba9d7c3751d49d347d035", [:mix], [], "hexpm", "7977f183127a7cbe9346981e2f480dc04c55ffddaef746bd58debd566070eef8"},
"nimble_pool": {:hex, :nimble_pool, "1.0.0", "5eb82705d138f4dd4423f69ceb19ac667b3b492ae570c9f5c900bb3d2f50a847", [:mix], [], "hexpm", "80be3b882d2d351882256087078e1b1952a28bf98d0a287be87e4a24a710b67a"},
"parse_trans": {:hex, :parse_trans, "3.3.1", "16328ab840cc09919bd10dab29e431da3af9e9e7e7e6f0089dd5a2d2820011d8", [:rebar3], [], "hexpm", "07cd9577885f56362d414e8c4c4e6bdf10d43a8767abb92d24cbe8b24c54888b"},
"parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"},
"phoenix": {:hex, :phoenix, "1.7.2", "c375ffb482beb4e3d20894f84dd7920442884f5f5b70b9f4528cbe0cedefec63", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.4", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "1ebca94b32b4d0e097ab2444a9742ed8ff3361acad17365e4e6b2e79b4792159"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"},
"phoenix_html": {:hex, :phoenix_html, "3.3.1", "4788757e804a30baac6b3fc9695bf5562465dd3f1da8eb8460ad5b404d9a2178", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "bed1906edd4906a15fd7b412b85b05e521e1f67c9a85418c55999277e553d0d3"},
@@ -57,16 +57,16 @@
"phoenix_swoosh": {:hex, :phoenix_swoosh, "1.2.0", "a544d83fde4a767efb78f45404a74c9e37b2a9c5ea3339692e65a6966731f935", [:mix], [{:finch, "~> 0.8", [hex: :finch, repo: "hexpm", optional: true]}, {:hackney, "~> 1.10", [hex: :hackney, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_html, "~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_view, "~> 1.0 or ~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:swoosh, "~> 1.5", [hex: :swoosh, repo: "hexpm", optional: false]}], "hexpm", "e88d117251e89a16b92222415a6d87b99a96747ddf674fc5c7631de734811dba"},
"phoenix_template": {:hex, :phoenix_template, "1.0.1", "85f79e3ad1b0180abb43f9725973e3b8c2c3354a87245f91431eec60553ed3ef", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "157dc078f6226334c91cb32c1865bf3911686f8bcd6bcff86736f6253e6993ee"},
"phoenix_view": {:hex, :phoenix_view, "2.0.2", "6bd4d2fd595ef80d33b439ede6a19326b78f0f1d8d62b9a318e3d9c1af351098", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "a929e7230ea5c7ee0e149ffcf44ce7cf7f4b6d2bfe1752dd7c084cdff152d36f"},
"plug": {:hex, :plug, "1.14.2", "cff7d4ec45b4ae176a227acd94a7ab536d9b37b942c8e8fa6dfc0fff98ff4d80", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "842fc50187e13cf4ac3b253d47d9474ed6c296a8732752835ce4a86acdf68d13"},
"plug": {:hex, :plug, "1.15.1", "b7efd81c1a1286f13efb3f769de343236bd8b7d23b4a9f40d3002fc39ad8f74c", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "459497bd94d041d98d948054ec6c0b76feacd28eec38b219ca04c0de13c79d30"},
"plug_cowboy": {:hex, :plug_cowboy, "2.6.1", "9a3bbfceeb65eff5f39dab529e5cd79137ac36e913c02067dba3963a26efe9b2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "de36e1a21f451a18b790f37765db198075c25875c64834bcc82d90b309eb6613"},
"plug_crypto": {:hex, :plug_crypto, "1.2.5", "918772575e48e81e455818229bf719d4ab4181fcbf7f85b68a35620f78d89ced", [:mix], [], "hexpm", "26549a1d6345e2172eb1c233866756ae44a9609bd33ee6f99147ab3fd87fd842"},
"porcelain": {:hex, :porcelain, "2.0.3", "2d77b17d1f21fed875b8c5ecba72a01533db2013bd2e5e62c6d286c029150fdc", [:mix], [], "hexpm", "dc996ab8fadbc09912c787c7ab8673065e50ea1a6245177b0c24569013d23620"},
"postgrex": {:hex, :postgrex, "0.17.1", "01c29fd1205940ee55f7addb8f1dc25618ca63a8817e56fac4f6846fc2cddcbe", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "14b057b488e73be2beee508fb1955d8db90d6485c6466428fe9ccf1d6692a555"},
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.6", "cf344f5692c82d2cd7554f5ec8fd961548d4fd09e7d22f5b62482e5aeaebd4b0", [:make, :mix, :rebar3], [], "hexpm", "bdb0d2471f453c88ff3908e7686f86f9be327d065cc1ec16fa4540197ea04680"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"},
"stripity_stripe": {:hex, :stripity_stripe, "2.13.0", "b9ea806fcf46e85232b75f2145c34770b17faa44c59cdd13ff493aaa6e84b4a9", [:mix], [{:hackney, "~> 1.15", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.1", [hex: :jason, repo: "hexpm", optional: false]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}, {:uri_query, "~> 0.1.2", [hex: :uri_query, repo: "hexpm", optional: false]}], "hexpm", "d6931ed9816552320f95428fd997edf15e99a913ca78fc4342d5516b98f42476"},
"sweet_xml": {:hex, :sweet_xml, "0.7.3", "debb256781c75ff6a8c5cbf7981146312b66f044a2898f453709a53e5031b45b", [:mix], [], "hexpm", "e110c867a1b3fe74bfc7dd9893aa851f0eed5518d0d7cad76d7baafd30e4f5ba"},
"swoosh": {:hex, :swoosh, "1.9.1", "0a5d7bf9954eb41d7e55525bc0940379982b090abbaef67cd8e1fd2ed7f8ca1a", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "76dffff3ffcab80f249d5937a592eaef7cc49ac6f4cdd27e622868326ed6371e"},
"sweet_xml": {:hex, :sweet_xml, "0.7.4", "a8b7e1ce7ecd775c7e8a65d501bc2cd933bff3a9c41ab763f5105688ef485d08", [:mix], [], "hexpm", "e7c4b0bdbf460c928234951def54fe87edf1a170f6896675443279e2dbeba167"},
"swoosh": {:hex, :swoosh, "1.12.0", "ecc85ee12947932986243299b8d28e6cdfc192c8d9e24c4c64f6738efdf344cb", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "87db7ab0f35e358ba5eac3afc7422ed0c8c168a2d219d2a83ad8cb7a424f6cc9"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"},
"telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"},

View File

@@ -15,10 +15,11 @@ msgstr ""
msgid "Settings"
msgstr "Einstellungen"
#: lib/claper_web/live/event_live/manage.ex:457
#: lib/claper_web/live/event_live/manage.ex:650
#: lib/claper_web/live/form_live/form_component.html.heex:37
#: lib/claper_web/live/user_settings_live/show.html.heex:34
#: lib/claper_web/templates/user_registration/new.html.heex:34
#: lib/claper_web/templates/user_reset_password/new.html.heex:33
#: lib/claper_web/templates/user_session/new.html.heex:47
#, elixir-autogen, elixir-format
msgid "Email"
@@ -30,6 +31,8 @@ msgid "Join the Claper experience"
msgstr "Werden Sie Teil der Claper Erfahrung"
#: lib/claper_web/templates/user_registration/new.html.heex:24
#: lib/claper_web/templates/user_reset_password/edit.html.heex:25
#: lib/claper_web/templates/user_reset_password/new.html.heex:24
#, elixir-autogen, elixir-format
msgid "Oops, check that all fields are filled in correctly."
msgstr "Überprüfen Sie, ob alle Felder korrekt ausgefüllt sind."
@@ -75,22 +78,22 @@ msgstr "Wir haben Ihnen eine E-Mail geschickt an"
msgid "Your personal informations only visible by you"
msgstr "Ihre persönlichen Informationen sind nur für Sie sichtbar"
#: lib/claper_web/live/event_live/show.html.heex:387
#: lib/claper_web/live/event_live/show.html.heex:405
#, elixir-autogen, elixir-format
msgid "days"
msgstr "Tage"
#: lib/claper_web/live/event_live/show.html.heex:393
#: lib/claper_web/live/event_live/show.html.heex:411
#, elixir-autogen, elixir-format
msgid "hours"
msgstr "Stunden"
#: lib/claper_web/live/event_live/show.html.heex:399
#: lib/claper_web/live/event_live/show.html.heex:417
#, elixir-autogen, elixir-format
msgid "minutes"
msgstr "Minuten"
#: lib/claper_web/live/event_live/show.html.heex:118
#: lib/claper_web/live/event_live/show.html.heex:136
#, elixir-autogen, elixir-format
msgid "Be the first to react !"
msgstr "Seien Sie der Erste, der reagiert!"
@@ -98,7 +101,7 @@ msgstr "Seien Sie der Erste, der reagiert!"
#: lib/claper_web/live/event_live/event_card_component.ex:98
#: lib/claper_web/live/event_live/join.ex:42
#: lib/claper_web/live/event_live/join.html.heex:106
#: lib/claper_web/live/event_live/show.html.heex:239
#: lib/claper_web/live/event_live/show.html.heex:257
#, elixir-autogen, elixir-format
msgid "Join"
msgstr "Teilnehmen"
@@ -111,12 +114,12 @@ msgid "Dashboard"
msgstr "Dashboard"
#: lib/claper_web/live/event_live/post_component.ex:33
#: lib/claper_web/live/event_live/post_component.ex:86
#: lib/claper_web/live/event_live/post_component.ex:112
#, elixir-autogen, elixir-format
msgid "Host"
msgstr "Host"
#: lib/claper_web/live/event_live/show.html.heex:405
#: lib/claper_web/live/event_live/show.html.heex:423
#, elixir-autogen, elixir-format
msgid "seconds"
msgstr "Sekunden"
@@ -127,7 +130,7 @@ msgid "Create your first presentation"
msgstr "Erstellen Sie Ihre erste Präsentation"
#: lib/claper_web/live/event_live/event_card_component.ex:50
#: lib/claper_web/live/event_live/manage.html.heex:80
#: lib/claper_web/live/event_live/manage.html.heex:81
#, elixir-autogen, elixir-format
msgid "Finish on"
msgstr "Endet um"
@@ -167,8 +170,8 @@ msgstr "Meine Präsentationen"
msgid "Name of your presentation"
msgstr "Name Ihrer Präsentation"
#: lib/claper_web/live/event_live/presenter.html.heex:21
#: lib/claper_web/live/event_live/show.html.heex:414
#: lib/claper_web/live/event_live/presenter.html.heex:26
#: lib/claper_web/live/event_live/show.html.heex:432
#, elixir-autogen, elixir-format
msgid "Scan to interact in real-time"
msgstr "Scannen und in Echtzeit interagieren"
@@ -178,7 +181,7 @@ msgstr "Scannen und in Echtzeit interagieren"
msgid "Starting on"
msgstr "Startet um"
#: lib/claper_web/live/event_live/event_form_component.ex:196
#: lib/claper_web/live/event_live/event_form_component.ex:206
#, elixir-autogen, elixir-format
msgid "Updated successfully"
msgstr "Erfolgreich aktualisiert"
@@ -205,12 +208,12 @@ msgstr "Es ist an der Zeit, Ihren Präsentationen mehr Bedeutung zu verleihen."
msgid "Return to home"
msgstr "Zurück zur Startseite"
#: lib/claper_web/live/event_live/event_form_component.ex:178
#: lib/claper_web/live/event_live/event_form_component.ex:186
#, elixir-autogen, elixir-format
msgid "Created successfully"
msgstr "Erfolgreich erstellt"
#: lib/claper_web/live/event_live/manage.ex:23
#: lib/claper_web/live/event_live/manage.ex:24
#: lib/claper_web/live/event_live/presenter.ex:21
#: lib/claper_web/live/event_live/show.ex:24
#, elixir-autogen, elixir-format
@@ -219,12 +222,13 @@ msgstr "Präsentation existiert nicht"
#: lib/claper_web/live/event_live/event_card_component.ex:109
#: lib/claper_web/live/event_live/event_card_component.ex:129
#: lib/claper_web/live/event_live/form_component.ex:96
#: lib/claper_web/live/event_live/form_component.ex:97
#: lib/claper_web/live/event_live/index.ex:65
#, elixir-autogen, elixir-format
msgid "Edit"
msgstr "Ändern"
#: lib/claper_web/live/embed_live/form_component.html.heex:51
#: lib/claper_web/live/event_live/event_form_component.html.heex:18
#: lib/claper_web/live/event_live/event_form_component.html.heex:25
#: lib/claper_web/live/event_live/index.ex:71
@@ -235,18 +239,21 @@ msgstr "Ändern"
msgid "Create"
msgstr "Erstellen"
#: lib/claper_web/live/embed_live/form_component.html.heex:56
#: lib/claper_web/live/event_live/event_card_component.ex:171
#: lib/claper_web/live/event_live/event_form_component.html.heex:30
#: lib/claper_web/live/event_live/manage.html.heex:631
#: lib/claper_web/live/event_live/manage.html.heex:731
#: lib/claper_web/live/event_live/post_component.ex:44
#: lib/claper_web/live/event_live/post_component.ex:116
#: lib/claper_web/live/event_live/manage.html.heex:835
#: lib/claper_web/live/event_live/manage.html.heex:1010
#: lib/claper_web/live/event_live/manage.html.heex:1125
#: lib/claper_web/live/event_live/post_component.ex:70
#: lib/claper_web/live/event_live/post_component.ex:142
#: lib/claper_web/live/form_live/form_component.html.heex:103
#: lib/claper_web/live/poll_live/form_component.html.heex:99
#, elixir-autogen, elixir-format
msgid "Delete"
msgstr "Löschen"
#: lib/claper_web/live/embed_live/form_component.html.heex:52
#: lib/claper_web/live/event_live/event_form_component.html.heex:17
#: lib/claper_web/live/event_live/event_form_component.html.heex:24
#: lib/claper_web/live/form_live/form_component.html.heex:99
@@ -310,8 +317,8 @@ msgid "You can log into your account by clicking here."
msgstr "Sie können sich bei Ihrem Konto anmelden, indem Sie hier klicken."
#: lib/claper_web/live/event_live/event_form_component.html.heex:34
#: lib/claper_web/live/event_live/post_component.ex:49
#: lib/claper_web/live/event_live/post_component.ex:121
#: lib/claper_web/live/event_live/post_component.ex:75
#: lib/claper_web/live/event_live/post_component.ex:147
#, elixir-autogen, elixir-format
msgid "Are you sure?"
msgstr "Sind Sie sicher?"
@@ -350,12 +357,12 @@ msgstr "Datei hochladen"
msgid "or drag and drop"
msgstr "oder drag and drop"
#: lib/claper_web/live/event_live/event_form_component.ex:229
#: lib/claper_web/live/event_live/event_form_component.ex:257
#, elixir-autogen, elixir-format
msgid "You have selected an incorrect file type"
msgstr "Sie haben einen falschen Dateityp ausgewählt"
#: lib/claper_web/live/event_live/event_form_component.ex:228
#: lib/claper_web/live/event_live/event_form_component.ex:256
#, elixir-autogen, elixir-format
msgid "Your file is too large"
msgstr "Ihre Datei ist zu groß"
@@ -370,12 +377,12 @@ msgstr "Datei ändern"
msgid "Presentation replaced"
msgstr "Präsentation ersetzt"
#: lib/claper_web/live/event_live/manage.html.heex:256
#: lib/claper_web/live/event_live/manage.html.heex:293
#, elixir-autogen, elixir-format
msgid "Edit poll"
msgstr "Umfrage bearbeiten"
#: lib/claper_web/live/event_live/manage.html.heex:255
#: lib/claper_web/live/event_live/manage.html.heex:292
#, elixir-autogen, elixir-format
msgid "New poll"
msgstr "Neue Umfrage"
@@ -385,18 +392,18 @@ msgstr "Neue Umfrage"
msgid "Title of your poll"
msgstr "Titel Ihrer Umfrage"
#: lib/claper_web/live/event_live/event_form_component.ex:230
#: lib/claper_web/live/event_live/event_form_component.ex:258
#, elixir-autogen, elixir-format
msgid "Upload failed"
msgstr "Hochladen fehlgeschlagen"
#: lib/claper_web/live/event_live/manage.html.heex:176
#: lib/claper_web/live/event_live/manage.html.heex:180
#, elixir-autogen, elixir-format
msgid "Add poll to know opinion of your public."
msgstr "Fügen Sie eine Umfrage hinzu, um die Meinung Ihres Publikums zu erfahren."
#: lib/claper_web/live/event_live/manage.html.heex:174
#: lib/claper_web/live/event_live/manage.html.heex:395
#: lib/claper_web/live/event_live/manage.html.heex:177
#: lib/claper_web/live/event_live/manage.html.heex:461
#, elixir-autogen, elixir-format
msgid "Poll"
msgstr "Umfrage"
@@ -418,8 +425,8 @@ msgstr "Aktuelle Umfrage"
msgid "See current poll"
msgstr "Aktuelle Umfrage anzeigen"
#: lib/claper_web/live/event_live/poll_component.ex:107
#: lib/claper_web/live/event_live/poll_component.ex:115
#: lib/claper_web/live/event_live/poll_component.ex:123
#: lib/claper_web/live/event_live/poll_component.ex:131
#, elixir-autogen, elixir-format
msgid "Vote"
msgstr "Abstimmen"
@@ -440,8 +447,9 @@ msgstr "Benutzer Email-Adresse"
msgid "Present/Customize"
msgstr "Vorstellen/Ändern"
#: lib/claper_web/live/event_live/manage.html.heex:408
#: lib/claper_web/live/event_live/manage.html.heex:484
#: lib/claper_web/live/event_live/manage.html.heex:479
#: lib/claper_web/live/event_live/manage.html.heex:561
#: lib/claper_web/live/event_live/manage.html.heex:635
#, elixir-autogen, elixir-format
msgid "Active"
msgstr "Aktiv"
@@ -451,12 +459,12 @@ msgstr "Aktiv"
msgid "Changing your file will remove all interaction elements like polls associated."
msgstr "Wenn Sie Ihre Datei ändern, werden alle damit verbundenen Interaktionselemente wie Umfragen entfernt."
#: lib/claper_web/live/event_live/manage.html.heex:584
#: lib/claper_web/live/event_live/manage.html.heex:752
#, elixir-autogen, elixir-format
msgid "Messages from attendees will appear here."
msgstr "Nachrichten von Teilnehmern werden hier erscheinen."
#: lib/claper_web/live/event_live/manage.html.heex:770
#: lib/claper_web/live/event_live/manage.html.heex:1170
#, elixir-autogen, elixir-format
msgid "On screen settings"
msgstr "Bildschirmeinstellungen"
@@ -471,29 +479,30 @@ msgstr "Verarbeitung der Datei..."
msgid "This will delete all responses associated and the poll itself, are you sure?"
msgstr "Dadurch werden alle zugehörigen Antworten und die Umfrage selbst gelöscht, sind Sie sicher?"
#: lib/claper_web/live/event_live/manage.html.heex:112
#: lib/claper_web/live/event_live/manage.html.heex:113
#, elixir-autogen, elixir-format
msgid "Start"
msgstr "Start"
#: lib/claper_web/live/event_live/manage.html.heex:88
#: lib/claper_web/live/event_live/manage.html.heex:89
#, elixir-autogen, elixir-format
msgid "Press <strong>F</strong> in the presentation window to enable fullscreen"
msgstr "Drücken Sie <strong>F</strong> im Präsentationsfenster, um den Vollbildmodus zu aktivieren"
#: lib/claper_web/live/event_live/show.html.heex:298
#: lib/claper_web/live/event_live/show.html.heex:316
#, elixir-autogen, elixir-format
msgid "Ask, comment..."
msgstr "Fragen, kommentieren..."
#: lib/claper_web/live/event_live/manage.html.heex:556
#: lib/claper_web/live/event_live/manage.html.heex:710
#: lib/claper_web/live/stat_live/index.html.heex:71
#, elixir-autogen, elixir-format
msgid "Messages"
msgstr "Nachrichten"
#: lib/claper_web/live/event_live/manage.html.heex:416
#: lib/claper_web/live/event_live/manage.html.heex:492
#: lib/claper_web/live/event_live/manage.html.heex:487
#: lib/claper_web/live/event_live/manage.html.heex:569
#: lib/claper_web/live/event_live/manage.html.heex:643
#, elixir-autogen, elixir-format
msgid "Set active"
msgstr "Aktivieren"
@@ -518,6 +527,7 @@ msgstr "Die Seite wird gerade gewartet, wir sind bald wieder da!"
msgid "Facilitators can present and manage interactions"
msgstr "Moderatoren können präsentieren und Interaktionen steuern"
#: lib/claper_web/templates/leader_notifier/invitation.html.heex:45
#: lib/claper_web/templates/user_notifier/change.html.heex:42
#: lib/claper_web/templates/user_notifier/magic.html.heex:42
#, elixir-autogen, elixir-format
@@ -529,26 +539,30 @@ msgstr "Wenn Sie Probleme mit der obigen Schaltfläche haben, kopieren Sie die f
msgid "You can change your email by visiting the URL below"
msgstr "Sie können Ihre E-Mail-Adresse ändern, indem Sie die folgende URL aufrufen"
#: lib/claper_web/live/event_live/manage.html.heex:525
#: lib/claper_web/live/event_live/manage.html.heex:678
#, elixir-autogen, elixir-format
msgid "Add interaction"
msgstr "Interaktion hinzufügen"
#: lib/claper_web/live/event_live/manage.html.heex:607
#: lib/claper_web/live/event_live/manage.html.heex:622
#: lib/claper_web/live/event_live/manage.html.heex:797
#: lib/claper_web/live/event_live/manage.html.heex:826
#: lib/claper_web/live/event_live/manage.html.heex:972
#: lib/claper_web/live/event_live/manage.html.heex:1001
#, elixir-autogen, elixir-format
msgid "Blocking this user will delete all his messages and he will not be able to join again, confirm ?"
msgstr "Wenn Sie diesen Benutzer sperren, werden alle seine Nachrichten gelöscht, und er kann nicht mehr beitreten. Bestätigen?"
#: lib/claper_web/live/event_live/show.ex:50
#: lib/claper_web/live/event_live/show.ex:197
#: lib/claper_web/live/event_live/show.ex:212
#: lib/claper_web/live/event_live/show.ex:198
#: lib/claper_web/live/event_live/show.ex:213
#, elixir-autogen, elixir-format
msgid "You have been banned from this event"
msgstr "Sie wurden von dieser Veranstaltung ausgeschlossen"
#: lib/claper_web/live/event_live/manage.html.heex:601
#: lib/claper_web/live/event_live/manage.html.heex:616
#: lib/claper_web/live/event_live/manage.html.heex:791
#: lib/claper_web/live/event_live/manage.html.heex:820
#: lib/claper_web/live/event_live/manage.html.heex:966
#: lib/claper_web/live/event_live/manage.html.heex:995
#, elixir-autogen, elixir-format
msgid "Ban"
msgstr "Ban"
@@ -642,7 +656,7 @@ msgstr "Veranstaltung"
msgid "Interactions history"
msgstr "Interaktionsgeschichte"
#: lib/claper_web/live/stat_live/index.html.heex:260
#: lib/claper_web/live/stat_live/index.html.heex:271
#, elixir-autogen, elixir-format
msgid "No messages has been sent"
msgstr "Es wurden keine Nachrichten gesendet"
@@ -702,19 +716,20 @@ msgstr "Anmeldung"
msgid "Connect to your account"
msgstr "Verbinden Sie sich mit Ihrem Konto"
#: lib/claper_web/live/event_live/show.html.heex:423
#: lib/claper_web/live/event_live/show.html.heex:441
#, elixir-autogen, elixir-format
msgid "Or use the code:"
msgstr "Oder verwenden Sie den Code:"
#: lib/claper_web/templates/user_registration/new.html.heex:51
#: lib/claper_web/templates/user_session/new.html.heex:73
#: lib/claper_web/templates/user_session/new.html.heex:77
#, elixir-autogen, elixir-format
msgid "Create account"
msgstr "Benutzerkonto erstellen"
#: lib/claper_web/live/user_settings_live/show.html.heex:116
#: lib/claper_web/templates/user_registration/new.html.heex:42
#: lib/claper_web/templates/user_reset_password/edit.html.heex:34
#: lib/claper_web/templates/user_session/new.html.heex:57
#, elixir-autogen, elixir-format
msgid "Password"
@@ -762,7 +777,7 @@ msgid_plural "Field %{count}"
msgstr[0] "Feld %{count}"
msgstr[1] "Feld %{count}"
#: lib/claper_web/live/event_live/manage.html.heex:213
#: lib/claper_web/live/event_live/manage.html.heex:219
#, elixir-autogen, elixir-format
msgid "Add form to collect data from your public."
msgstr "Fügen Sie ein Formular hinzu, um Daten von Ihrem Publikum zu sammeln."
@@ -772,34 +787,34 @@ msgstr "Fügen Sie ein Formular hinzu, um Daten von Ihrem Publikum zu sammeln."
msgid "Current form"
msgstr "Aktuelles Formular"
#: lib/claper_web/live/event_live/manage.html.heex:277
#: lib/claper_web/live/event_live/manage.html.heex:314
#, elixir-autogen, elixir-format
msgid "Edit form"
msgstr "Formular bearbeiten"
#: lib/claper_web/live/event_live/manage.html.heex:211
#: lib/claper_web/live/event_live/manage.html.heex:471
#: lib/claper_web/live/event_live/manage.html.heex:216
#: lib/claper_web/live/event_live/manage.html.heex:543
#: lib/claper_web/live/stat_live/index.html.heex:215
#, elixir-autogen, elixir-format
msgid "Form"
msgstr "Formular"
#: lib/claper_web/live/event_live/manage.html.heex:559
#: lib/claper_web/live/event_live/manage.html.heex:722
#, elixir-autogen, elixir-format
msgid "Form submissions"
msgstr "Abgeschickte Formulare"
#: lib/claper_web/live/event_live/manage.html.heex:711
#: lib/claper_web/live/event_live/manage.html.heex:1104
#, elixir-autogen, elixir-format
msgid "Form submissions from attendees will appear here."
msgstr "Formulareinsendungen der Teilnehmer werden hier angezeigt."
#: lib/claper_web/live/event_live/manage.ex:456
#: lib/claper_web/live/event_live/manage.ex:649
#, elixir-autogen, elixir-format
msgid "Name"
msgstr "Name"
#: lib/claper_web/live/event_live/manage.html.heex:276
#: lib/claper_web/live/event_live/manage.html.heex:313
#, elixir-autogen, elixir-format
msgid "New form"
msgstr "Neues Formular"
@@ -814,7 +829,7 @@ msgstr "Es wurde kein Formular gesendet"
msgid "See current form"
msgstr "Siehe aktuelles Formular"
#: lib/claper_web/live/event_live/form_component.ex:96
#: lib/claper_web/live/event_live/form_component.ex:97
#, elixir-autogen, elixir-format
msgid "Submit"
msgstr "Abschicken"
@@ -824,7 +839,7 @@ msgstr "Abschicken"
msgid "Text"
msgstr "Text"
#: lib/claper_web/live/event_live/manage.html.heex:736
#: lib/claper_web/live/event_live/manage.html.heex:1130
#, elixir-autogen, elixir-format
msgid "This cannot be undone, confirm ?"
msgstr "Dies kann nicht rückgängig gemacht werden. Bestätigen?"
@@ -864,22 +879,22 @@ msgstr "Wählen Sie eine oder mehrere Optionen aus"
msgid "Multiple answers"
msgstr "Mehrere Antworten"
#: lib/claper_web/live/event_live/manage.html.heex:244
#: lib/claper_web/live/event_live/manage.html.heex:281
#, elixir-autogen, elixir-format
msgid "Import all interactions from another presentation"
msgstr "Importieren Sie alle Interaktionen aus einer anderen Präsentation"
#: lib/claper_web/live/event_live/manage.ex:183
#: lib/claper_web/live/event_live/manage.ex:226
#, elixir-autogen, elixir-format
msgid "Interactions import failed"
msgstr "Der Import der Interaktionen ist fehlgeschlagen"
#: lib/claper_web/live/event_live/manage.ex:176
#: lib/claper_web/live/event_live/manage.ex:219
#, elixir-autogen, elixir-format
msgid "Interactions imported successfully"
msgstr "Interaktionen erfolgreich importiert"
#: lib/claper_web/live/event_live/manage.html.heex:295
#: lib/claper_web/live/event_live/manage.html.heex:354
#, elixir-autogen, elixir-format
msgid "Select presentation"
msgstr "Präsentation auswählen"
@@ -889,70 +904,70 @@ msgstr "Präsentation auswählen"
msgid "PDF, PPT, PPTX up to %{size} MB"
msgstr "PDF, PPT, PPTX bis zu %{size} MB"
#: lib/claper_web/live/event_live/manage.html.heex:796
#: lib/claper_web/live/event_live/manage.html.heex:1215
#, elixir-autogen, elixir-format
msgid "Attendees settings"
msgstr "Teilnehmereinstellungen"
#: lib/claper_web/live/event_live/manage.html.heex:800
#: lib/claper_web/live/event_live/manage.html.heex:1224
#, elixir-autogen, elixir-format
msgid "Enable messages"
msgstr "Nachrichten aktivieren"
#: lib/claper_web/live/event_live/manage.html.heex:777
#: lib/claper_web/live/event_live/manage.html.heex:1179
#, elixir-autogen, elixir-format
msgid "Show instructions"
msgstr "Anleitung anzeigen"
#: lib/claper_web/live/event_live/manage.html.heex:782
#: lib/claper_web/live/event_live/manage.html.heex:1188
#, elixir-autogen, elixir-format
msgid "Show messages"
msgstr "Nachrichten anzeigen"
#: lib/claper_web/live/event_live/manage.html.heex:791
#: lib/claper_web/live/event_live/manage.html.heex:1209
#, elixir-autogen, elixir-format
msgid "Show poll results"
msgstr "Umfrageergebnisse anzeigen"
#: lib/claper_web/live/event_live/show.html.heex:318
#: lib/claper_web/live/event_live/show.html.heex:336
#, elixir-autogen, elixir-format
msgid "Messages deactivated"
msgstr "Nachrichten deaktiviert"
#: lib/claper_web/live/event_live/show.html.heex:161
#: lib/claper_web/live/event_live/show.html.heex:182
#: lib/claper_web/live/event_live/show.html.heex:282
#: lib/claper_web/live/event_live/show.html.heex:179
#: lib/claper_web/live/event_live/show.html.heex:200
#: lib/claper_web/live/event_live/show.html.heex:300
#, elixir-autogen, elixir-format
msgid "Anonymous"
msgstr ""
msgstr "Anonymous"
#: lib/claper_web/live/event_live/show.html.heex:208
#: lib/claper_web/live/event_live/show.html.heex:226
#, elixir-autogen, elixir-format
msgid "Close"
msgstr ""
msgstr "Schließen"
#: lib/claper_web/live/event_live/manage.html.heex:808
#: lib/claper_web/live/event_live/manage.html.heex:1234
#, elixir-autogen, elixir-format, fuzzy
msgid "Enable anonymous messages"
msgstr "Nachrichten aktivieren"
msgstr "Anonyme Nachrichten aktivieren"
#: lib/claper_web/live/event_live/show.html.heex:189
#: lib/claper_web/live/event_live/show.html.heex:234
#: lib/claper_web/live/event_live/show.html.heex:207
#: lib/claper_web/live/event_live/show.html.heex:252
#, elixir-autogen, elixir-format, fuzzy
msgid "Enter your name"
msgstr "Benutze deinen Namen"
#: lib/claper_web/live/event_live/presenter.html.heex:33
#: lib/claper_web/live/event_live/presenter.html.heex:38
#, elixir-autogen, elixir-format
msgid "Or go to %{url} and use the code:"
msgstr "Oder gehen Sie zu %{url} und verwenden Sie den Code:"
#: lib/claper_web/live/event_live/show.html.heex:202
#: lib/claper_web/live/event_live/show.html.heex:220
#, elixir-autogen, elixir-format
msgid "Use your name"
msgstr "Benutze deinen Namen"
#: lib/claper_web/live/event_live/show.html.heex:182
#: lib/claper_web/live/event_live/show.html.heex:200
#, elixir-autogen, elixir-format
msgid "disabled"
msgstr "deaktiviert"
@@ -961,3 +976,168 @@ msgstr "deaktiviert"
#, elixir-autogen, elixir-format
msgid "Account creation is disabled"
msgstr "Kontoerstellung ist deaktiviert"
#: lib/claper_web/live/event_live/manage.html.heex:250
#, elixir-autogen, elixir-format
msgid "Add a Youtube video or any web content."
msgstr "Fügen Sie ein YouTube-Video oder einen beliebigen Webinhalt hinzu."
#: lib/claper_web/templates/user_reset_password/edit.html.heex:51
#, elixir-autogen, elixir-format
msgid "Confirm new password"
msgstr "Neues Passwort bestätigen"
#: lib/claper_web/templates/user_session/new.html.heex:72
#, elixir-autogen, elixir-format
msgid "Forgot your password?"
msgstr "Passwort vergessen?"
#: lib/claper_web/controllers/user_reset_password_controller.ex:26
#, elixir-autogen, elixir-format
msgid "If your email is in our system, you'll receive instructions to reset your password shortly."
msgstr "Wenn sich Ihre E-Mail-Adresse in unserem System befindet, erhalten Sie in Kürze Anweisungen zum Zurücksetzen Ihres Passworts."
#: lib/claper_web/templates/user_reset_password/edit.html.heex:42
#, elixir-autogen, elixir-format
msgid "Password confirmation"
msgstr "Passwort bestätigen"
#: lib/claper_web/controllers/user_reset_password_controller.ex:44
#, elixir-autogen, elixir-format
msgid "Password updated successfully."
msgstr "Passwort erfolgreich aktualisiert."
#: lib/claper_web/controllers/user_reset_password_controller.ex:59
#, elixir-autogen, elixir-format
msgid "Reset password link is invalid or it has expired."
msgstr "Der Link zum Zurücksetzen des Kennworts ist ungültig oder er ist abgelaufen."
#: lib/claper_web/templates/user_reset_password/edit.html.heex:12
#: lib/claper_web/templates/user_reset_password/new.html.heex:12
#, elixir-autogen, elixir-format, fuzzy
msgid "Reset your password"
msgstr "Aktualisieren Sie Ihr Passwort"
#: lib/claper_web/templates/user_reset_password/new.html.heex:41
#, elixir-autogen, elixir-format
msgid "Send link to reset password"
msgstr "Link zum Zurücksetzen des Passworts senden"
#: lib/claper_web/live/embed_live/form_component.html.heex:38
#, elixir-autogen, elixir-format
msgid "Attendee can view the web content on their device"
msgstr "Der Teilnehmer kann die Webinhalte auf seinem Gerät anzeigen"
#: lib/claper_web/live/event_live/embed_component.ex:59
#, elixir-autogen, elixir-format, fuzzy
msgid "Current web content"
msgstr "Aktuelle Einbettung"
#: lib/claper_web/live/event_live/manage.html.heex:335
#, elixir-autogen, elixir-format
msgid "Edit web content"
msgstr "Webinhalt bearbeiten"
#: lib/claper_web/live/event_live/manage.html.heex:334
#, elixir-autogen, elixir-format
msgid "New web content"
msgstr "Neuer Webinhalt"
#: lib/claper_web/live/event_live/embed_component.ex:36
#, elixir-autogen, elixir-format, fuzzy
msgid "See current web content"
msgstr "Aktuellen Webinhalt anzeigen"
#: lib/claper_web/live/embed_live/form_component.html.heex:25
#, elixir-autogen, elixir-format
msgid "The iframe component"
msgstr "Die iframe-Komponente"
#: lib/claper_web/live/embed_live/form_component.html.heex:62
#, elixir-autogen, elixir-format, fuzzy
msgid "This will delete the web content, are you sure?"
msgstr "Dies wird den Webinhalt löschen, sind Sie sicher?"
#: lib/claper_web/live/embed_live/form_component.html.heex:14
#, elixir-autogen, elixir-format
msgid "Title"
msgstr "Titel"
#: lib/claper_web/live/event_live/manage.html.heex:248
#: lib/claper_web/live/event_live/manage.html.heex:618
#: lib/claper_web/live/stat_live/index.html.heex:257
#, elixir-autogen, elixir-format
msgid "Web content"
msgstr "Webinhalt"
#: lib/claper/embeds/embed.ex:38
#, elixir-autogen, elixir-format, fuzzy
msgid "Invalid embed format (should start with <iframe> and end with </iframe>)"
msgstr "Ungültiges Einbettungsformat (sollte mit <iframe> beginnen und mit </iframe> enden)"
#: lib/claper_web/live/event_live/manage.html.heex:781
#: lib/claper_web/live/event_live/manage.html.heex:810
#: lib/claper_web/live/event_live/manage.html.heex:956
#: lib/claper_web/live/event_live/manage.html.heex:985
#, elixir-autogen, elixir-format
msgid "Pin"
msgstr "Anpinnen"
#: lib/claper_web/live/event_live/post_component.ex:59
#: lib/claper_web/live/event_live/post_component.ex:175
#, elixir-autogen, elixir-format
msgid "Pinned"
msgstr "Angepinnt"
#: lib/claper_web/live/event_live/manage.html.heex:714
#, elixir-autogen, elixir-format, fuzzy
msgid "Pinned messages"
msgstr "Angepinnte Nachrichten"
#: lib/claper_web/live/event_live/manage.html.heex:925
#, elixir-autogen, elixir-format
msgid "Pinned messages will appear here."
msgstr "Angepinnte Beiträge werden hier angezeigt."
#: lib/claper_web/live/event_live/manage.html.heex:1198
#, elixir-autogen, elixir-format
msgid "Show only pinned messages"
msgstr "Nur angepinnte Nachrichten anzeigen"
#: lib/claper_web/live/event_live/manage.html.heex:779
#: lib/claper_web/live/event_live/manage.html.heex:808
#: lib/claper_web/live/event_live/manage.html.heex:954
#: lib/claper_web/live/event_live/manage.html.heex:983
#, elixir-autogen, elixir-format
msgid "Unpin"
msgstr "Lösen"
#: lib/claper_web/templates/leader_notifier/invitation.html.heex:35
#, elixir-autogen, elixir-format
msgid "Login or create account"
msgstr "Einloggen oder Konto erstellen"
#: lib/claper_web/templates/leader_notifier/invitation.html.heex:22
#, elixir-autogen, elixir-format
msgid "Someone invited you to manage the event: %{name}"
msgstr "Jemand hat Sie eingeladen, das Ereignis zu verwalten: %{name}"
#: lib/claper_web/templates/leader_notifier/invitation.html.heex:25
#, elixir-autogen, elixir-format
msgid "To accept the invitation, please login or create an account with this email: %{email}"
msgstr "Um die Einladung anzunehmen, melden Sie sich bitte an oder erstellen Sie ein Konto mit dieser E-Mail: %{email}"
#: lib/claper_web/templates/leader_notifier/invitation.html.heex:17
#, elixir-autogen, elixir-format
msgid "You have been invited"
msgstr "Sie wurden eingeladen"
#: lib/claper_web/notifiers/leader_notifier.ex:12
#, elixir-autogen, elixir-format
msgid "You have been invited to manage an event"
msgstr "Sie wurden eingeladen, ein Ereignis zu verwalten"
#: lib/claper_web/live/event_live/form_component.ex:103
#, elixir-autogen, elixir-format, fuzzy
msgid "Saved"
msgstr "Gespeichert"

View File

@@ -17,10 +17,11 @@ msgstr ""
msgid "Settings"
msgstr ""
#: lib/claper_web/live/event_live/manage.ex:457
#: lib/claper_web/live/event_live/manage.ex:650
#: lib/claper_web/live/form_live/form_component.html.heex:37
#: lib/claper_web/live/user_settings_live/show.html.heex:34
#: lib/claper_web/templates/user_registration/new.html.heex:34
#: lib/claper_web/templates/user_reset_password/new.html.heex:33
#: lib/claper_web/templates/user_session/new.html.heex:47
#, elixir-autogen, elixir-format
msgid "Email"
@@ -32,6 +33,8 @@ msgid "Join the Claper experience"
msgstr ""
#: lib/claper_web/templates/user_registration/new.html.heex:24
#: lib/claper_web/templates/user_reset_password/edit.html.heex:25
#: lib/claper_web/templates/user_reset_password/new.html.heex:24
#, elixir-autogen, elixir-format
msgid "Oops, check that all fields are filled in correctly."
msgstr ""
@@ -77,22 +80,22 @@ msgstr ""
msgid "Your personal informations only visible by you"
msgstr ""
#: lib/claper_web/live/event_live/show.html.heex:387
#: lib/claper_web/live/event_live/show.html.heex:405
#, elixir-autogen, elixir-format
msgid "days"
msgstr ""
#: lib/claper_web/live/event_live/show.html.heex:393
#: lib/claper_web/live/event_live/show.html.heex:411
#, elixir-autogen, elixir-format
msgid "hours"
msgstr ""
#: lib/claper_web/live/event_live/show.html.heex:399
#: lib/claper_web/live/event_live/show.html.heex:417
#, elixir-autogen, elixir-format
msgid "minutes"
msgstr ""
#: lib/claper_web/live/event_live/show.html.heex:118
#: lib/claper_web/live/event_live/show.html.heex:136
#, elixir-autogen, elixir-format
msgid "Be the first to react !"
msgstr ""
@@ -100,7 +103,7 @@ msgstr ""
#: lib/claper_web/live/event_live/event_card_component.ex:98
#: lib/claper_web/live/event_live/join.ex:42
#: lib/claper_web/live/event_live/join.html.heex:106
#: lib/claper_web/live/event_live/show.html.heex:239
#: lib/claper_web/live/event_live/show.html.heex:257
#, elixir-autogen, elixir-format
msgid "Join"
msgstr ""
@@ -113,12 +116,12 @@ msgid "Dashboard"
msgstr ""
#: lib/claper_web/live/event_live/post_component.ex:33
#: lib/claper_web/live/event_live/post_component.ex:86
#: lib/claper_web/live/event_live/post_component.ex:112
#, elixir-autogen, elixir-format
msgid "Host"
msgstr ""
#: lib/claper_web/live/event_live/show.html.heex:405
#: lib/claper_web/live/event_live/show.html.heex:423
#, elixir-autogen, elixir-format
msgid "seconds"
msgstr ""
@@ -129,7 +132,7 @@ msgid "Create your first presentation"
msgstr ""
#: lib/claper_web/live/event_live/event_card_component.ex:50
#: lib/claper_web/live/event_live/manage.html.heex:80
#: lib/claper_web/live/event_live/manage.html.heex:81
#, elixir-autogen, elixir-format
msgid "Finish on"
msgstr ""
@@ -169,8 +172,8 @@ msgstr ""
msgid "Name of your presentation"
msgstr ""
#: lib/claper_web/live/event_live/presenter.html.heex:21
#: lib/claper_web/live/event_live/show.html.heex:414
#: lib/claper_web/live/event_live/presenter.html.heex:26
#: lib/claper_web/live/event_live/show.html.heex:432
#, elixir-autogen, elixir-format
msgid "Scan to interact in real-time"
msgstr ""
@@ -180,7 +183,7 @@ msgstr ""
msgid "Starting on"
msgstr ""
#: lib/claper_web/live/event_live/event_form_component.ex:196
#: lib/claper_web/live/event_live/event_form_component.ex:206
#, elixir-autogen, elixir-format
msgid "Updated successfully"
msgstr ""
@@ -207,12 +210,12 @@ msgstr ""
msgid "Return to home"
msgstr ""
#: lib/claper_web/live/event_live/event_form_component.ex:178
#: lib/claper_web/live/event_live/event_form_component.ex:186
#, elixir-autogen, elixir-format
msgid "Created successfully"
msgstr ""
#: lib/claper_web/live/event_live/manage.ex:23
#: lib/claper_web/live/event_live/manage.ex:24
#: lib/claper_web/live/event_live/presenter.ex:21
#: lib/claper_web/live/event_live/show.ex:24
#, elixir-autogen, elixir-format
@@ -221,12 +224,13 @@ msgstr ""
#: lib/claper_web/live/event_live/event_card_component.ex:109
#: lib/claper_web/live/event_live/event_card_component.ex:129
#: lib/claper_web/live/event_live/form_component.ex:96
#: lib/claper_web/live/event_live/form_component.ex:97
#: lib/claper_web/live/event_live/index.ex:65
#, elixir-autogen, elixir-format
msgid "Edit"
msgstr ""
#: lib/claper_web/live/embed_live/form_component.html.heex:51
#: lib/claper_web/live/event_live/event_form_component.html.heex:18
#: lib/claper_web/live/event_live/event_form_component.html.heex:25
#: lib/claper_web/live/event_live/index.ex:71
@@ -237,18 +241,21 @@ msgstr ""
msgid "Create"
msgstr ""
#: lib/claper_web/live/embed_live/form_component.html.heex:56
#: lib/claper_web/live/event_live/event_card_component.ex:171
#: lib/claper_web/live/event_live/event_form_component.html.heex:30
#: lib/claper_web/live/event_live/manage.html.heex:631
#: lib/claper_web/live/event_live/manage.html.heex:731
#: lib/claper_web/live/event_live/post_component.ex:44
#: lib/claper_web/live/event_live/post_component.ex:116
#: lib/claper_web/live/event_live/manage.html.heex:835
#: lib/claper_web/live/event_live/manage.html.heex:1010
#: lib/claper_web/live/event_live/manage.html.heex:1125
#: lib/claper_web/live/event_live/post_component.ex:70
#: lib/claper_web/live/event_live/post_component.ex:142
#: lib/claper_web/live/form_live/form_component.html.heex:103
#: lib/claper_web/live/poll_live/form_component.html.heex:99
#, elixir-autogen, elixir-format
msgid "Delete"
msgstr ""
#: lib/claper_web/live/embed_live/form_component.html.heex:52
#: lib/claper_web/live/event_live/event_form_component.html.heex:17
#: lib/claper_web/live/event_live/event_form_component.html.heex:24
#: lib/claper_web/live/form_live/form_component.html.heex:99
@@ -312,8 +319,8 @@ msgid "You can log into your account by clicking here."
msgstr ""
#: lib/claper_web/live/event_live/event_form_component.html.heex:34
#: lib/claper_web/live/event_live/post_component.ex:49
#: lib/claper_web/live/event_live/post_component.ex:121
#: lib/claper_web/live/event_live/post_component.ex:75
#: lib/claper_web/live/event_live/post_component.ex:147
#, elixir-autogen, elixir-format
msgid "Are you sure?"
msgstr ""
@@ -352,12 +359,12 @@ msgstr ""
msgid "or drag and drop"
msgstr ""
#: lib/claper_web/live/event_live/event_form_component.ex:229
#: lib/claper_web/live/event_live/event_form_component.ex:257
#, elixir-autogen, elixir-format
msgid "You have selected an incorrect file type"
msgstr ""
#: lib/claper_web/live/event_live/event_form_component.ex:228
#: lib/claper_web/live/event_live/event_form_component.ex:256
#, elixir-autogen, elixir-format
msgid "Your file is too large"
msgstr ""
@@ -372,12 +379,12 @@ msgstr ""
msgid "Presentation replaced"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:256
#: lib/claper_web/live/event_live/manage.html.heex:293
#, elixir-autogen, elixir-format
msgid "Edit poll"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:255
#: lib/claper_web/live/event_live/manage.html.heex:292
#, elixir-autogen, elixir-format
msgid "New poll"
msgstr ""
@@ -387,18 +394,18 @@ msgstr ""
msgid "Title of your poll"
msgstr ""
#: lib/claper_web/live/event_live/event_form_component.ex:230
#: lib/claper_web/live/event_live/event_form_component.ex:258
#, elixir-autogen, elixir-format
msgid "Upload failed"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:176
#: lib/claper_web/live/event_live/manage.html.heex:180
#, elixir-autogen, elixir-format
msgid "Add poll to know opinion of your public."
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:174
#: lib/claper_web/live/event_live/manage.html.heex:395
#: lib/claper_web/live/event_live/manage.html.heex:177
#: lib/claper_web/live/event_live/manage.html.heex:461
#, elixir-autogen, elixir-format
msgid "Poll"
msgstr ""
@@ -420,8 +427,8 @@ msgstr ""
msgid "See current poll"
msgstr ""
#: lib/claper_web/live/event_live/poll_component.ex:107
#: lib/claper_web/live/event_live/poll_component.ex:115
#: lib/claper_web/live/event_live/poll_component.ex:123
#: lib/claper_web/live/event_live/poll_component.ex:131
#, elixir-autogen, elixir-format
msgid "Vote"
msgstr ""
@@ -442,8 +449,9 @@ msgstr ""
msgid "Present/Customize"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:408
#: lib/claper_web/live/event_live/manage.html.heex:484
#: lib/claper_web/live/event_live/manage.html.heex:479
#: lib/claper_web/live/event_live/manage.html.heex:561
#: lib/claper_web/live/event_live/manage.html.heex:635
#, elixir-autogen, elixir-format
msgid "Active"
msgstr ""
@@ -453,12 +461,12 @@ msgstr ""
msgid "Changing your file will remove all interaction elements like polls associated."
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:584
#: lib/claper_web/live/event_live/manage.html.heex:752
#, elixir-autogen, elixir-format
msgid "Messages from attendees will appear here."
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:770
#: lib/claper_web/live/event_live/manage.html.heex:1170
#, elixir-autogen, elixir-format
msgid "On screen settings"
msgstr ""
@@ -473,29 +481,30 @@ msgstr ""
msgid "This will delete all responses associated and the poll itself, are you sure?"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:112
#: lib/claper_web/live/event_live/manage.html.heex:113
#, elixir-autogen, elixir-format
msgid "Start"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:88
#: lib/claper_web/live/event_live/manage.html.heex:89
#, elixir-autogen, elixir-format
msgid "Press <strong>F</strong> in the presentation window to enable fullscreen"
msgstr ""
#: lib/claper_web/live/event_live/show.html.heex:298
#: lib/claper_web/live/event_live/show.html.heex:316
#, elixir-autogen, elixir-format
msgid "Ask, comment..."
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:556
#: lib/claper_web/live/event_live/manage.html.heex:710
#: lib/claper_web/live/stat_live/index.html.heex:71
#, elixir-autogen, elixir-format
msgid "Messages"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:416
#: lib/claper_web/live/event_live/manage.html.heex:492
#: lib/claper_web/live/event_live/manage.html.heex:487
#: lib/claper_web/live/event_live/manage.html.heex:569
#: lib/claper_web/live/event_live/manage.html.heex:643
#, elixir-autogen, elixir-format
msgid "Set active"
msgstr ""
@@ -520,6 +529,7 @@ msgstr ""
msgid "Facilitators can present and manage interactions"
msgstr ""
#: lib/claper_web/templates/leader_notifier/invitation.html.heex:45
#: lib/claper_web/templates/user_notifier/change.html.heex:42
#: lib/claper_web/templates/user_notifier/magic.html.heex:42
#, elixir-autogen, elixir-format
@@ -531,26 +541,30 @@ msgstr ""
msgid "You can change your email by visiting the URL below"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:525
#: lib/claper_web/live/event_live/manage.html.heex:678
#, elixir-autogen, elixir-format
msgid "Add interaction"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:607
#: lib/claper_web/live/event_live/manage.html.heex:622
#: lib/claper_web/live/event_live/manage.html.heex:797
#: lib/claper_web/live/event_live/manage.html.heex:826
#: lib/claper_web/live/event_live/manage.html.heex:972
#: lib/claper_web/live/event_live/manage.html.heex:1001
#, elixir-autogen, elixir-format
msgid "Blocking this user will delete all his messages and he will not be able to join again, confirm ?"
msgstr ""
#: lib/claper_web/live/event_live/show.ex:50
#: lib/claper_web/live/event_live/show.ex:197
#: lib/claper_web/live/event_live/show.ex:212
#: lib/claper_web/live/event_live/show.ex:198
#: lib/claper_web/live/event_live/show.ex:213
#, elixir-autogen, elixir-format
msgid "You have been banned from this event"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:601
#: lib/claper_web/live/event_live/manage.html.heex:616
#: lib/claper_web/live/event_live/manage.html.heex:791
#: lib/claper_web/live/event_live/manage.html.heex:820
#: lib/claper_web/live/event_live/manage.html.heex:966
#: lib/claper_web/live/event_live/manage.html.heex:995
#, elixir-autogen, elixir-format
msgid "Ban"
msgstr ""
@@ -644,7 +658,7 @@ msgstr ""
msgid "Interactions history"
msgstr ""
#: lib/claper_web/live/stat_live/index.html.heex:260
#: lib/claper_web/live/stat_live/index.html.heex:271
#, elixir-autogen, elixir-format
msgid "No messages has been sent"
msgstr ""
@@ -704,19 +718,20 @@ msgstr ""
msgid "Connect to your account"
msgstr ""
#: lib/claper_web/live/event_live/show.html.heex:423
#: lib/claper_web/live/event_live/show.html.heex:441
#, elixir-autogen, elixir-format
msgid "Or use the code:"
msgstr ""
#: lib/claper_web/templates/user_registration/new.html.heex:51
#: lib/claper_web/templates/user_session/new.html.heex:73
#: lib/claper_web/templates/user_session/new.html.heex:77
#, elixir-autogen, elixir-format
msgid "Create account"
msgstr ""
#: lib/claper_web/live/user_settings_live/show.html.heex:116
#: lib/claper_web/templates/user_registration/new.html.heex:42
#: lib/claper_web/templates/user_reset_password/edit.html.heex:34
#: lib/claper_web/templates/user_session/new.html.heex:57
#, elixir-autogen, elixir-format
msgid "Password"
@@ -764,7 +779,7 @@ msgid_plural "Field %{count}"
msgstr[0] ""
msgstr[1] ""
#: lib/claper_web/live/event_live/manage.html.heex:213
#: lib/claper_web/live/event_live/manage.html.heex:219
#, elixir-autogen, elixir-format
msgid "Add form to collect data from your public."
msgstr ""
@@ -774,34 +789,34 @@ msgstr ""
msgid "Current form"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:277
#: lib/claper_web/live/event_live/manage.html.heex:314
#, elixir-autogen, elixir-format
msgid "Edit form"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:211
#: lib/claper_web/live/event_live/manage.html.heex:471
#: lib/claper_web/live/event_live/manage.html.heex:216
#: lib/claper_web/live/event_live/manage.html.heex:543
#: lib/claper_web/live/stat_live/index.html.heex:215
#, elixir-autogen, elixir-format
msgid "Form"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:559
#: lib/claper_web/live/event_live/manage.html.heex:722
#, elixir-autogen, elixir-format
msgid "Form submissions"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:711
#: lib/claper_web/live/event_live/manage.html.heex:1104
#, elixir-autogen, elixir-format
msgid "Form submissions from attendees will appear here."
msgstr ""
#: lib/claper_web/live/event_live/manage.ex:456
#: lib/claper_web/live/event_live/manage.ex:649
#, elixir-autogen, elixir-format
msgid "Name"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:276
#: lib/claper_web/live/event_live/manage.html.heex:313
#, elixir-autogen, elixir-format
msgid "New form"
msgstr ""
@@ -816,7 +831,7 @@ msgstr ""
msgid "See current form"
msgstr ""
#: lib/claper_web/live/event_live/form_component.ex:96
#: lib/claper_web/live/event_live/form_component.ex:97
#, elixir-autogen, elixir-format
msgid "Submit"
msgstr ""
@@ -826,7 +841,7 @@ msgstr ""
msgid "Text"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:736
#: lib/claper_web/live/event_live/manage.html.heex:1130
#, elixir-autogen, elixir-format
msgid "This cannot be undone, confirm ?"
msgstr ""
@@ -866,22 +881,22 @@ msgstr ""
msgid "Multiple answers"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:244
#: lib/claper_web/live/event_live/manage.html.heex:281
#, elixir-autogen, elixir-format
msgid "Import all interactions from another presentation"
msgstr ""
#: lib/claper_web/live/event_live/manage.ex:183
#: lib/claper_web/live/event_live/manage.ex:226
#, elixir-autogen, elixir-format
msgid "Interactions import failed"
msgstr ""
#: lib/claper_web/live/event_live/manage.ex:176
#: lib/claper_web/live/event_live/manage.ex:219
#, elixir-autogen, elixir-format
msgid "Interactions imported successfully"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:295
#: lib/claper_web/live/event_live/manage.html.heex:354
#, elixir-autogen, elixir-format
msgid "Select presentation"
msgstr ""
@@ -891,70 +906,70 @@ msgstr ""
msgid "PDF, PPT, PPTX up to %{size} MB"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:796
#: lib/claper_web/live/event_live/manage.html.heex:1215
#, elixir-autogen, elixir-format
msgid "Attendees settings"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:800
#: lib/claper_web/live/event_live/manage.html.heex:1224
#, elixir-autogen, elixir-format
msgid "Enable messages"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:777
#: lib/claper_web/live/event_live/manage.html.heex:1179
#, elixir-autogen, elixir-format
msgid "Show instructions"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:782
#: lib/claper_web/live/event_live/manage.html.heex:1188
#, elixir-autogen, elixir-format
msgid "Show messages"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:791
#: lib/claper_web/live/event_live/manage.html.heex:1209
#, elixir-autogen, elixir-format
msgid "Show poll results"
msgstr ""
#: lib/claper_web/live/event_live/show.html.heex:318
#: lib/claper_web/live/event_live/show.html.heex:336
#, elixir-autogen, elixir-format
msgid "Messages deactivated"
msgstr ""
#: lib/claper_web/live/event_live/show.html.heex:161
#: lib/claper_web/live/event_live/show.html.heex:182
#: lib/claper_web/live/event_live/show.html.heex:282
#: lib/claper_web/live/event_live/show.html.heex:179
#: lib/claper_web/live/event_live/show.html.heex:200
#: lib/claper_web/live/event_live/show.html.heex:300
#, elixir-autogen, elixir-format
msgid "Anonymous"
msgstr ""
#: lib/claper_web/live/event_live/show.html.heex:208
#: lib/claper_web/live/event_live/show.html.heex:226
#, elixir-autogen, elixir-format
msgid "Close"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:808
#: lib/claper_web/live/event_live/manage.html.heex:1234
#, elixir-autogen, elixir-format
msgid "Enable anonymous messages"
msgstr ""
#: lib/claper_web/live/event_live/show.html.heex:189
#: lib/claper_web/live/event_live/show.html.heex:234
#: lib/claper_web/live/event_live/show.html.heex:207
#: lib/claper_web/live/event_live/show.html.heex:252
#, elixir-autogen, elixir-format
msgid "Enter your name"
msgstr ""
#: lib/claper_web/live/event_live/presenter.html.heex:33
#: lib/claper_web/live/event_live/presenter.html.heex:38
#, elixir-autogen, elixir-format
msgid "Or go to %{url} and use the code:"
msgstr ""
#: lib/claper_web/live/event_live/show.html.heex:202
#: lib/claper_web/live/event_live/show.html.heex:220
#, elixir-autogen, elixir-format
msgid "Use your name"
msgstr ""
#: lib/claper_web/live/event_live/show.html.heex:182
#: lib/claper_web/live/event_live/show.html.heex:200
#, elixir-autogen, elixir-format
msgid "disabled"
msgstr ""
@@ -963,3 +978,168 @@ msgstr ""
#, elixir-autogen, elixir-format
msgid "Account creation is disabled"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:250
#, elixir-autogen, elixir-format
msgid "Add a Youtube video or any web content."
msgstr ""
#: lib/claper_web/templates/user_reset_password/edit.html.heex:51
#, elixir-autogen, elixir-format
msgid "Confirm new password"
msgstr ""
#: lib/claper_web/templates/user_session/new.html.heex:72
#, elixir-autogen, elixir-format
msgid "Forgot your password?"
msgstr ""
#: lib/claper_web/controllers/user_reset_password_controller.ex:26
#, elixir-autogen, elixir-format
msgid "If your email is in our system, you'll receive instructions to reset your password shortly."
msgstr ""
#: lib/claper_web/templates/user_reset_password/edit.html.heex:42
#, elixir-autogen, elixir-format
msgid "Password confirmation"
msgstr ""
#: lib/claper_web/controllers/user_reset_password_controller.ex:44
#, elixir-autogen, elixir-format
msgid "Password updated successfully."
msgstr ""
#: lib/claper_web/controllers/user_reset_password_controller.ex:59
#, elixir-autogen, elixir-format
msgid "Reset password link is invalid or it has expired."
msgstr ""
#: lib/claper_web/templates/user_reset_password/edit.html.heex:12
#: lib/claper_web/templates/user_reset_password/new.html.heex:12
#, elixir-autogen, elixir-format
msgid "Reset your password"
msgstr ""
#: lib/claper_web/templates/user_reset_password/new.html.heex:41
#, elixir-autogen, elixir-format
msgid "Send link to reset password"
msgstr ""
#: lib/claper_web/live/embed_live/form_component.html.heex:38
#, elixir-autogen, elixir-format
msgid "Attendee can view the web content on their device"
msgstr ""
#: lib/claper_web/live/event_live/embed_component.ex:59
#, elixir-autogen, elixir-format
msgid "Current web content"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:335
#, elixir-autogen, elixir-format
msgid "Edit web content"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:334
#, elixir-autogen, elixir-format
msgid "New web content"
msgstr ""
#: lib/claper_web/live/event_live/embed_component.ex:36
#, elixir-autogen, elixir-format
msgid "See current web content"
msgstr ""
#: lib/claper_web/live/embed_live/form_component.html.heex:25
#, elixir-autogen, elixir-format
msgid "The iframe component"
msgstr ""
#: lib/claper_web/live/embed_live/form_component.html.heex:62
#, elixir-autogen, elixir-format
msgid "This will delete the web content, are you sure?"
msgstr ""
#: lib/claper_web/live/embed_live/form_component.html.heex:14
#, elixir-autogen, elixir-format
msgid "Title"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:248
#: lib/claper_web/live/event_live/manage.html.heex:618
#: lib/claper_web/live/stat_live/index.html.heex:257
#, elixir-autogen, elixir-format
msgid "Web content"
msgstr ""
#: lib/claper/embeds/embed.ex:38
#, elixir-autogen, elixir-format
msgid "Invalid embed format (should start with <iframe> and end with </iframe>)"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:781
#: lib/claper_web/live/event_live/manage.html.heex:810
#: lib/claper_web/live/event_live/manage.html.heex:956
#: lib/claper_web/live/event_live/manage.html.heex:985
#, elixir-autogen, elixir-format
msgid "Pin"
msgstr ""
#: lib/claper_web/live/event_live/post_component.ex:59
#: lib/claper_web/live/event_live/post_component.ex:175
#, elixir-autogen, elixir-format
msgid "Pinned"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:714
#, elixir-autogen, elixir-format
msgid "Pinned messages"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:925
#, elixir-autogen, elixir-format
msgid "Pinned messages will appear here."
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:1198
#, elixir-autogen, elixir-format
msgid "Show only pinned messages"
msgstr ""
#: lib/claper_web/live/event_live/manage.html.heex:779
#: lib/claper_web/live/event_live/manage.html.heex:808
#: lib/claper_web/live/event_live/manage.html.heex:954
#: lib/claper_web/live/event_live/manage.html.heex:983
#, elixir-autogen, elixir-format
msgid "Unpin"
msgstr ""
#: lib/claper_web/templates/leader_notifier/invitation.html.heex:35
#, elixir-autogen, elixir-format
msgid "Login or create account"
msgstr ""
#: lib/claper_web/templates/leader_notifier/invitation.html.heex:22
#, elixir-autogen, elixir-format
msgid "Someone invited you to manage the event: %{name}"
msgstr ""
#: lib/claper_web/templates/leader_notifier/invitation.html.heex:25
#, elixir-autogen, elixir-format
msgid "To accept the invitation, please login or create an account with this email: %{email}"
msgstr ""
#: lib/claper_web/templates/leader_notifier/invitation.html.heex:17
#, elixir-autogen, elixir-format
msgid "You have been invited"
msgstr ""
#: lib/claper_web/notifiers/leader_notifier.ex:12
#, elixir-autogen, elixir-format
msgid "You have been invited to manage an event"
msgstr ""
#: lib/claper_web/live/event_live/form_component.ex:103
#, elixir-autogen, elixir-format
msgid "Saved"
msgstr ""

File diff suppressed because it is too large Load Diff

View File

@@ -15,10 +15,11 @@ msgstr ""
msgid "Settings"
msgstr "Paramètres"
#: lib/claper_web/live/event_live/manage.ex:457
#: lib/claper_web/live/event_live/manage.ex:650
#: lib/claper_web/live/form_live/form_component.html.heex:37
#: lib/claper_web/live/user_settings_live/show.html.heex:34
#: lib/claper_web/templates/user_registration/new.html.heex:34
#: lib/claper_web/templates/user_reset_password/new.html.heex:33
#: lib/claper_web/templates/user_session/new.html.heex:47
#, elixir-autogen, elixir-format
msgid "Email"
@@ -30,6 +31,8 @@ msgid "Join the Claper experience"
msgstr "Rejoignez l'expérience Claper"
#: lib/claper_web/templates/user_registration/new.html.heex:24
#: lib/claper_web/templates/user_reset_password/edit.html.heex:25
#: lib/claper_web/templates/user_reset_password/new.html.heex:24
#, elixir-autogen, elixir-format
msgid "Oops, check that all fields are filled in correctly."
msgstr "Oups, vérifiez que tous les champs sont remplis correctement."
@@ -75,22 +78,22 @@ msgstr "Nous vous avons envoyé un email à"
msgid "Your personal informations only visible by you"
msgstr "Vos informations personnelles ne sont visibles que par vous"
#: lib/claper_web/live/event_live/show.html.heex:387
#: lib/claper_web/live/event_live/show.html.heex:405
#, elixir-autogen, elixir-format
msgid "days"
msgstr "jours"
#: lib/claper_web/live/event_live/show.html.heex:393
#: lib/claper_web/live/event_live/show.html.heex:411
#, elixir-autogen, elixir-format
msgid "hours"
msgstr "heures"
#: lib/claper_web/live/event_live/show.html.heex:399
#: lib/claper_web/live/event_live/show.html.heex:417
#, elixir-autogen, elixir-format
msgid "minutes"
msgstr "minutes"
#: lib/claper_web/live/event_live/show.html.heex:118
#: lib/claper_web/live/event_live/show.html.heex:136
#, elixir-autogen, elixir-format
msgid "Be the first to react !"
msgstr "Soyez le premier à réagir !"
@@ -98,7 +101,7 @@ msgstr "Soyez le premier à réagir !"
#: lib/claper_web/live/event_live/event_card_component.ex:98
#: lib/claper_web/live/event_live/join.ex:42
#: lib/claper_web/live/event_live/join.html.heex:106
#: lib/claper_web/live/event_live/show.html.heex:239
#: lib/claper_web/live/event_live/show.html.heex:257
#, elixir-autogen, elixir-format
msgid "Join"
msgstr "Rejoindre"
@@ -111,12 +114,12 @@ msgid "Dashboard"
msgstr "Tableau de bord"
#: lib/claper_web/live/event_live/post_component.ex:33
#: lib/claper_web/live/event_live/post_component.ex:86
#: lib/claper_web/live/event_live/post_component.ex:112
#, elixir-autogen, elixir-format
msgid "Host"
msgstr "Animateur"
#: lib/claper_web/live/event_live/show.html.heex:405
#: lib/claper_web/live/event_live/show.html.heex:423
#, elixir-autogen, elixir-format
msgid "seconds"
msgstr "secondes"
@@ -127,7 +130,7 @@ msgid "Create your first presentation"
msgstr "Créez votre première présentation"
#: lib/claper_web/live/event_live/event_card_component.ex:50
#: lib/claper_web/live/event_live/manage.html.heex:80
#: lib/claper_web/live/event_live/manage.html.heex:81
#, elixir-autogen, elixir-format
msgid "Finish on"
msgstr "Termine le"
@@ -167,8 +170,8 @@ msgstr "Mes présentations"
msgid "Name of your presentation"
msgstr "Nom de votre présentation"
#: lib/claper_web/live/event_live/presenter.html.heex:21
#: lib/claper_web/live/event_live/show.html.heex:414
#: lib/claper_web/live/event_live/presenter.html.heex:26
#: lib/claper_web/live/event_live/show.html.heex:432
#, elixir-autogen, elixir-format
msgid "Scan to interact in real-time"
msgstr "Scannez pour interagir en temps réel"
@@ -178,7 +181,7 @@ msgstr "Scannez pour interagir en temps réel"
msgid "Starting on"
msgstr "Commence le"
#: lib/claper_web/live/event_live/event_form_component.ex:196
#: lib/claper_web/live/event_live/event_form_component.ex:206
#, elixir-autogen, elixir-format
msgid "Updated successfully"
msgstr "Mis à jour avec succès"
@@ -205,12 +208,12 @@ msgstr "C'est le moment de propulser vos présentations."
msgid "Return to home"
msgstr "Retourner à l'accueil"
#: lib/claper_web/live/event_live/event_form_component.ex:178
#: lib/claper_web/live/event_live/event_form_component.ex:186
#, elixir-autogen, elixir-format
msgid "Created successfully"
msgstr "Mis à jour avec succès"
#: lib/claper_web/live/event_live/manage.ex:23
#: lib/claper_web/live/event_live/manage.ex:24
#: lib/claper_web/live/event_live/presenter.ex:21
#: lib/claper_web/live/event_live/show.ex:24
#, elixir-autogen, elixir-format
@@ -219,12 +222,13 @@ msgstr "La présentation n'existe pas"
#: lib/claper_web/live/event_live/event_card_component.ex:109
#: lib/claper_web/live/event_live/event_card_component.ex:129
#: lib/claper_web/live/event_live/form_component.ex:96
#: lib/claper_web/live/event_live/form_component.ex:97
#: lib/claper_web/live/event_live/index.ex:65
#, elixir-autogen, elixir-format
msgid "Edit"
msgstr "Modifier"
#: lib/claper_web/live/embed_live/form_component.html.heex:51
#: lib/claper_web/live/event_live/event_form_component.html.heex:18
#: lib/claper_web/live/event_live/event_form_component.html.heex:25
#: lib/claper_web/live/event_live/index.ex:71
@@ -235,18 +239,21 @@ msgstr "Modifier"
msgid "Create"
msgstr "Créer"
#: lib/claper_web/live/embed_live/form_component.html.heex:56
#: lib/claper_web/live/event_live/event_card_component.ex:171
#: lib/claper_web/live/event_live/event_form_component.html.heex:30
#: lib/claper_web/live/event_live/manage.html.heex:631
#: lib/claper_web/live/event_live/manage.html.heex:731
#: lib/claper_web/live/event_live/post_component.ex:44
#: lib/claper_web/live/event_live/post_component.ex:116
#: lib/claper_web/live/event_live/manage.html.heex:835
#: lib/claper_web/live/event_live/manage.html.heex:1010
#: lib/claper_web/live/event_live/manage.html.heex:1125
#: lib/claper_web/live/event_live/post_component.ex:70
#: lib/claper_web/live/event_live/post_component.ex:142
#: lib/claper_web/live/form_live/form_component.html.heex:103
#: lib/claper_web/live/poll_live/form_component.html.heex:99
#, elixir-autogen, elixir-format
msgid "Delete"
msgstr "Supprimer"
#: lib/claper_web/live/embed_live/form_component.html.heex:52
#: lib/claper_web/live/event_live/event_form_component.html.heex:17
#: lib/claper_web/live/event_live/event_form_component.html.heex:24
#: lib/claper_web/live/form_live/form_component.html.heex:99
@@ -310,8 +317,8 @@ msgid "You can log into your account by clicking here."
msgstr "Vous pouvez vous connecter à votre compte en cliquant ici."
#: lib/claper_web/live/event_live/event_form_component.html.heex:34
#: lib/claper_web/live/event_live/post_component.ex:49
#: lib/claper_web/live/event_live/post_component.ex:121
#: lib/claper_web/live/event_live/post_component.ex:75
#: lib/claper_web/live/event_live/post_component.ex:147
#, elixir-autogen, elixir-format
msgid "Are you sure?"
msgstr "Êtes-vous sûr?"
@@ -350,12 +357,12 @@ msgstr "Chargez un fichier"
msgid "or drag and drop"
msgstr "ou glisser-déposer"
#: lib/claper_web/live/event_live/event_form_component.ex:229
#: lib/claper_web/live/event_live/event_form_component.ex:257
#, elixir-autogen, elixir-format
msgid "You have selected an incorrect file type"
msgstr "Vous avez sélectionné un type de fichier incorrect"
#: lib/claper_web/live/event_live/event_form_component.ex:228
#: lib/claper_web/live/event_live/event_form_component.ex:256
#, elixir-autogen, elixir-format
msgid "Your file is too large"
msgstr "Votre fichier est trop volumineux"
@@ -370,12 +377,12 @@ msgstr "Changer le fichier"
msgid "Presentation replaced"
msgstr "Présentation remplacée"
#: lib/claper_web/live/event_live/manage.html.heex:256
#: lib/claper_web/live/event_live/manage.html.heex:293
#, elixir-autogen, elixir-format
msgid "Edit poll"
msgstr "Modifier le sondage"
#: lib/claper_web/live/event_live/manage.html.heex:255
#: lib/claper_web/live/event_live/manage.html.heex:292
#, elixir-autogen, elixir-format
msgid "New poll"
msgstr "Nouveau sondage"
@@ -385,18 +392,18 @@ msgstr "Nouveau sondage"
msgid "Title of your poll"
msgstr "Titre de votre sondage"
#: lib/claper_web/live/event_live/event_form_component.ex:230
#: lib/claper_web/live/event_live/event_form_component.ex:258
#, elixir-autogen, elixir-format
msgid "Upload failed"
msgstr "Échec du chargement"
#: lib/claper_web/live/event_live/manage.html.heex:176
#: lib/claper_web/live/event_live/manage.html.heex:180
#, elixir-autogen, elixir-format
msgid "Add poll to know opinion of your public."
msgstr "Ajoutez un sondage pour connaître l'opinion de votre public."
#: lib/claper_web/live/event_live/manage.html.heex:174
#: lib/claper_web/live/event_live/manage.html.heex:395
#: lib/claper_web/live/event_live/manage.html.heex:177
#: lib/claper_web/live/event_live/manage.html.heex:461
#, elixir-autogen, elixir-format
msgid "Poll"
msgstr "Sondage"
@@ -419,8 +426,8 @@ msgstr "Sondage actuel"
msgid "See current poll"
msgstr "Voir le sondage"
#: lib/claper_web/live/event_live/poll_component.ex:107
#: lib/claper_web/live/event_live/poll_component.ex:115
#: lib/claper_web/live/event_live/poll_component.ex:123
#: lib/claper_web/live/event_live/poll_component.ex:131
#, elixir-autogen, elixir-format
msgid "Vote"
msgstr "Voter"
@@ -441,8 +448,9 @@ msgstr "Adresse email"
msgid "Present/Customize"
msgstr "Présenter/Personnaliser"
#: lib/claper_web/live/event_live/manage.html.heex:408
#: lib/claper_web/live/event_live/manage.html.heex:484
#: lib/claper_web/live/event_live/manage.html.heex:479
#: lib/claper_web/live/event_live/manage.html.heex:561
#: lib/claper_web/live/event_live/manage.html.heex:635
#, elixir-autogen, elixir-format
msgid "Active"
msgstr "Actif"
@@ -452,12 +460,12 @@ msgstr "Actif"
msgid "Changing your file will remove all interaction elements like polls associated."
msgstr "La modification de votre fichier supprimera tous les éléments d'interaction comme les sondages associés."
#: lib/claper_web/live/event_live/manage.html.heex:584
#: lib/claper_web/live/event_live/manage.html.heex:752
#, elixir-autogen, elixir-format
msgid "Messages from attendees will appear here."
msgstr "Les messages des participants apparaîtront ici."
#: lib/claper_web/live/event_live/manage.html.heex:770
#: lib/claper_web/live/event_live/manage.html.heex:1170
#, elixir-autogen, elixir-format
msgid "On screen settings"
msgstr "Paramètres écran"
@@ -472,29 +480,30 @@ msgstr "Traitement de votre fichier..."
msgid "This will delete all responses associated and the poll itself, are you sure?"
msgstr "Cela supprimera toutes les réponses associées et le sondage lui-même, êtes-vous sûr ?"
#: lib/claper_web/live/event_live/manage.html.heex:112
#: lib/claper_web/live/event_live/manage.html.heex:113
#, elixir-autogen, elixir-format
msgid "Start"
msgstr "Démarrer"
#: lib/claper_web/live/event_live/manage.html.heex:88
#: lib/claper_web/live/event_live/manage.html.heex:89
#, elixir-autogen, elixir-format
msgid "Press <strong>F</strong> in the presentation window to enable fullscreen"
msgstr "Appuyez sur <strong>F</strong> dans la fenêtre de présentation pour activer le plein écran"
#: lib/claper_web/live/event_live/show.html.heex:298
#: lib/claper_web/live/event_live/show.html.heex:316
#, elixir-autogen, elixir-format
msgid "Ask, comment..."
msgstr "Questionnez, commentez..."
#: lib/claper_web/live/event_live/manage.html.heex:556
#: lib/claper_web/live/event_live/manage.html.heex:710
#: lib/claper_web/live/stat_live/index.html.heex:71
#, elixir-autogen, elixir-format
msgid "Messages"
msgstr "Messages"
#: lib/claper_web/live/event_live/manage.html.heex:416
#: lib/claper_web/live/event_live/manage.html.heex:492
#: lib/claper_web/live/event_live/manage.html.heex:487
#: lib/claper_web/live/event_live/manage.html.heex:569
#: lib/claper_web/live/event_live/manage.html.heex:643
#, elixir-autogen, elixir-format
msgid "Set active"
msgstr "Activer"
@@ -519,6 +528,7 @@ msgstr "Le site est en cours de maintenance, nous serons de retour très bientô
msgid "Facilitators can present and manage interactions"
msgstr "Les animateurs peuvent présenter et gérer les interactions"
#: lib/claper_web/templates/leader_notifier/invitation.html.heex:45
#: lib/claper_web/templates/user_notifier/change.html.heex:42
#: lib/claper_web/templates/user_notifier/magic.html.heex:42
#, elixir-autogen, elixir-format
@@ -530,26 +540,30 @@ msgstr "Si vous rencontrez des difficultés avec le bouton ci-dessus, copiez et
msgid "You can change your email by visiting the URL below"
msgstr "Vous pouvez modifier votre email en visitant l'URL ci-dessous"
#: lib/claper_web/live/event_live/manage.html.heex:525
#: lib/claper_web/live/event_live/manage.html.heex:678
#, elixir-autogen, elixir-format, fuzzy
msgid "Add interaction"
msgstr "Ajouter une interaction"
#: lib/claper_web/live/event_live/manage.html.heex:607
#: lib/claper_web/live/event_live/manage.html.heex:622
#: lib/claper_web/live/event_live/manage.html.heex:797
#: lib/claper_web/live/event_live/manage.html.heex:826
#: lib/claper_web/live/event_live/manage.html.heex:972
#: lib/claper_web/live/event_live/manage.html.heex:1001
#, elixir-autogen, elixir-format
msgid "Blocking this user will delete all his messages and he will not be able to join again, confirm ?"
msgstr "Bloquer cet utilisateur supprimera tous ses messages et il ne pourra pas rejoindre à nouveau, confirmer ?"
#: lib/claper_web/live/event_live/show.ex:50
#: lib/claper_web/live/event_live/show.ex:197
#: lib/claper_web/live/event_live/show.ex:212
#: lib/claper_web/live/event_live/show.ex:198
#: lib/claper_web/live/event_live/show.ex:213
#, elixir-autogen, elixir-format
msgid "You have been banned from this event"
msgstr "Vous avez été banni de cet événement"
#: lib/claper_web/live/event_live/manage.html.heex:601
#: lib/claper_web/live/event_live/manage.html.heex:616
#: lib/claper_web/live/event_live/manage.html.heex:791
#: lib/claper_web/live/event_live/manage.html.heex:820
#: lib/claper_web/live/event_live/manage.html.heex:966
#: lib/claper_web/live/event_live/manage.html.heex:995
#, elixir-autogen, elixir-format
msgid "Ban"
msgstr "Bannir"
@@ -645,7 +659,7 @@ msgstr "Événement"
msgid "Interactions history"
msgstr "Historique des interactions"
#: lib/claper_web/live/stat_live/index.html.heex:260
#: lib/claper_web/live/stat_live/index.html.heex:271
#, elixir-autogen, elixir-format
msgid "No messages has been sent"
msgstr "Aucun message n'a été envoyé"
@@ -706,19 +720,20 @@ msgstr "Connexion"
msgid "Connect to your account"
msgstr "Connectez-vous à votre compte"
#: lib/claper_web/live/event_live/show.html.heex:423
#: lib/claper_web/live/event_live/show.html.heex:441
#, elixir-autogen, elixir-format
msgid "Or use the code:"
msgstr "Ou utilisez le code:"
#: lib/claper_web/templates/user_registration/new.html.heex:51
#: lib/claper_web/templates/user_session/new.html.heex:73
#: lib/claper_web/templates/user_session/new.html.heex:77
#, elixir-autogen, elixir-format, fuzzy
msgid "Create account"
msgstr "Créer un compte"
#: lib/claper_web/live/user_settings_live/show.html.heex:116
#: lib/claper_web/templates/user_registration/new.html.heex:42
#: lib/claper_web/templates/user_reset_password/edit.html.heex:34
#: lib/claper_web/templates/user_session/new.html.heex:57
#, elixir-autogen, elixir-format
msgid "Password"
@@ -767,7 +782,7 @@ msgstr[0] "Champ %{count}"
msgstr[1] "Champ %{count}"
msgstr[2] "Champ %{count}"
#: lib/claper_web/live/event_live/manage.html.heex:213
#: lib/claper_web/live/event_live/manage.html.heex:219
#, elixir-autogen, elixir-format
msgid "Add form to collect data from your public."
msgstr "Ajoutez un formulaire pour recueillir les données de votre public."
@@ -777,34 +792,34 @@ msgstr "Ajoutez un formulaire pour recueillir les données de votre public."
msgid "Current form"
msgstr "Sondage actuel"
#: lib/claper_web/live/event_live/manage.html.heex:277
#: lib/claper_web/live/event_live/manage.html.heex:314
#, elixir-autogen, elixir-format, fuzzy
msgid "Edit form"
msgstr "Modifier"
#: lib/claper_web/live/event_live/manage.html.heex:211
#: lib/claper_web/live/event_live/manage.html.heex:471
#: lib/claper_web/live/event_live/manage.html.heex:216
#: lib/claper_web/live/event_live/manage.html.heex:543
#: lib/claper_web/live/stat_live/index.html.heex:215
#, elixir-autogen, elixir-format
msgid "Form"
msgstr "Formulaire"
#: lib/claper_web/live/event_live/manage.html.heex:559
#: lib/claper_web/live/event_live/manage.html.heex:722
#, elixir-autogen, elixir-format
msgid "Form submissions"
msgstr "Soumissions de formulaire"
#: lib/claper_web/live/event_live/manage.html.heex:711
#: lib/claper_web/live/event_live/manage.html.heex:1104
#, elixir-autogen, elixir-format
msgid "Form submissions from attendees will appear here."
msgstr "Les formulaires soumis par les participants apparaîtront ici."
#: lib/claper_web/live/event_live/manage.ex:456
#: lib/claper_web/live/event_live/manage.ex:649
#, elixir-autogen, elixir-format
msgid "Name"
msgstr "Nom"
#: lib/claper_web/live/event_live/manage.html.heex:276
#: lib/claper_web/live/event_live/manage.html.heex:313
#, elixir-autogen, elixir-format
msgid "New form"
msgstr "Nouveau formulaire"
@@ -819,7 +834,7 @@ msgstr "Aucun formulaire n'a été envoyé"
msgid "See current form"
msgstr "Voir le formulaire"
#: lib/claper_web/live/event_live/form_component.ex:96
#: lib/claper_web/live/event_live/form_component.ex:97
#, elixir-autogen, elixir-format
msgid "Submit"
msgstr "Soumettre"
@@ -829,7 +844,7 @@ msgstr "Soumettre"
msgid "Text"
msgstr "Texte"
#: lib/claper_web/live/event_live/manage.html.heex:736
#: lib/claper_web/live/event_live/manage.html.heex:1130
#, elixir-autogen, elixir-format
msgid "This cannot be undone, confirm ?"
msgstr "Cela ne peut pas être annulé, confirmez-vous ?"
@@ -869,22 +884,22 @@ msgstr "Sélectionner une ou plusieurs options"
msgid "Multiple answers"
msgstr "Réponses multiples"
#: lib/claper_web/live/event_live/manage.html.heex:244
#: lib/claper_web/live/event_live/manage.html.heex:281
#, elixir-autogen, elixir-format
msgid "Import all interactions from another presentation"
msgstr "Importer toutes les interactions d'une autre présentation"
#: lib/claper_web/live/event_live/manage.ex:183
#: lib/claper_web/live/event_live/manage.ex:226
#, elixir-autogen, elixir-format
msgid "Interactions import failed"
msgstr "Échec de l'importation d'interactions"
#: lib/claper_web/live/event_live/manage.ex:176
#: lib/claper_web/live/event_live/manage.ex:219
#, elixir-autogen, elixir-format
msgid "Interactions imported successfully"
msgstr "Interactions importées avec succès"
#: lib/claper_web/live/event_live/manage.html.heex:295
#: lib/claper_web/live/event_live/manage.html.heex:354
#, elixir-autogen, elixir-format
msgid "Select presentation"
msgstr "Sélectionnez la présentation"
@@ -894,70 +909,70 @@ msgstr "Sélectionnez la présentation"
msgid "PDF, PPT, PPTX up to %{size} MB"
msgstr "PDF, PPT, PPTX jusqu'à %{size} MB"
#: lib/claper_web/live/event_live/manage.html.heex:796
#: lib/claper_web/live/event_live/manage.html.heex:1215
#, elixir-autogen, elixir-format
msgid "Attendees settings"
msgstr "Paramètres participants"
#: lib/claper_web/live/event_live/manage.html.heex:800
#: lib/claper_web/live/event_live/manage.html.heex:1224
#, elixir-autogen, elixir-format
msgid "Enable messages"
msgstr "Activer messages"
#: lib/claper_web/live/event_live/manage.html.heex:777
#: lib/claper_web/live/event_live/manage.html.heex:1179
#, elixir-autogen, elixir-format
msgid "Show instructions"
msgstr "Afficher instructions"
#: lib/claper_web/live/event_live/manage.html.heex:782
#: lib/claper_web/live/event_live/manage.html.heex:1188
#, elixir-autogen, elixir-format
msgid "Show messages"
msgstr "Afficher messages"
#: lib/claper_web/live/event_live/manage.html.heex:791
#: lib/claper_web/live/event_live/manage.html.heex:1209
#, elixir-autogen, elixir-format
msgid "Show poll results"
msgstr "Afficher résultats sondage"
#: lib/claper_web/live/event_live/show.html.heex:318
#: lib/claper_web/live/event_live/show.html.heex:336
#, elixir-autogen, elixir-format
msgid "Messages deactivated"
msgstr "Messages désactivés"
#: lib/claper_web/live/event_live/show.html.heex:161
#: lib/claper_web/live/event_live/show.html.heex:182
#: lib/claper_web/live/event_live/show.html.heex:282
#: lib/claper_web/live/event_live/show.html.heex:179
#: lib/claper_web/live/event_live/show.html.heex:200
#: lib/claper_web/live/event_live/show.html.heex:300
#, elixir-autogen, elixir-format
msgid "Anonymous"
msgstr "Anonyme"
#: lib/claper_web/live/event_live/show.html.heex:208
#: lib/claper_web/live/event_live/show.html.heex:226
#, elixir-autogen, elixir-format
msgid "Close"
msgstr "Fermer"
#: lib/claper_web/live/event_live/manage.html.heex:808
#: lib/claper_web/live/event_live/manage.html.heex:1234
#, elixir-autogen, elixir-format, fuzzy
msgid "Enable anonymous messages"
msgstr "Activer messages anonymes"
#: lib/claper_web/live/event_live/show.html.heex:189
#: lib/claper_web/live/event_live/show.html.heex:234
#: lib/claper_web/live/event_live/show.html.heex:207
#: lib/claper_web/live/event_live/show.html.heex:252
#, elixir-autogen, elixir-format
msgid "Enter your name"
msgstr "Entrer votre nom"
#: lib/claper_web/live/event_live/presenter.html.heex:33
#: lib/claper_web/live/event_live/presenter.html.heex:38
#, elixir-autogen, elixir-format
msgid "Or go to %{url} and use the code:"
msgstr "Ou allez sur %{url} et utilisez le code:"
#: lib/claper_web/live/event_live/show.html.heex:202
#: lib/claper_web/live/event_live/show.html.heex:220
#, elixir-autogen, elixir-format
msgid "Use your name"
msgstr "Utiliser votre nom"
#: lib/claper_web/live/event_live/show.html.heex:182
#: lib/claper_web/live/event_live/show.html.heex:200
#, elixir-autogen, elixir-format
msgid "disabled"
msgstr "désactivé"
@@ -966,3 +981,168 @@ msgstr "désactivé"
#, elixir-autogen, elixir-format
msgid "Account creation is disabled"
msgstr "La création de compte est désactivée"
#: lib/claper_web/live/event_live/manage.html.heex:250
#, elixir-autogen, elixir-format
msgid "Add a Youtube video or any web content."
msgstr "Ajoutez une vidéo Youtube ou tout autre contenu web."
#: lib/claper_web/templates/user_reset_password/edit.html.heex:51
#, elixir-autogen, elixir-format
msgid "Confirm new password"
msgstr "Confirmer le nouveau mot de passe"
#: lib/claper_web/templates/user_session/new.html.heex:72
#, elixir-autogen, elixir-format
msgid "Forgot your password?"
msgstr "Mot de passe oublié ?"
#: lib/claper_web/controllers/user_reset_password_controller.ex:26
#, elixir-autogen, elixir-format
msgid "If your email is in our system, you'll receive instructions to reset your password shortly."
msgstr "Si votre adresse électronique se trouve dans notre système, vous recevrez sous peu des instructions pour réinitialiser votre mot de passe."
#: lib/claper_web/templates/user_reset_password/edit.html.heex:42
#, elixir-autogen, elixir-format
msgid "Password confirmation"
msgstr "Confirmation du mot de passe"
#: lib/claper_web/controllers/user_reset_password_controller.ex:44
#, elixir-autogen, elixir-format
msgid "Password updated successfully."
msgstr "Le mot de passe a été mis à jour."
#: lib/claper_web/controllers/user_reset_password_controller.ex:59
#, elixir-autogen, elixir-format
msgid "Reset password link is invalid or it has expired."
msgstr "Le lien de réinitialisation du mot de passe n'est pas valide ou a expiré."
#: lib/claper_web/templates/user_reset_password/edit.html.heex:12
#: lib/claper_web/templates/user_reset_password/new.html.heex:12
#, elixir-autogen, elixir-format, fuzzy
msgid "Reset your password"
msgstr "Changer votre mot de passe"
#: lib/claper_web/templates/user_reset_password/new.html.heex:41
#, elixir-autogen, elixir-format
msgid "Send link to reset password"
msgstr "Envoyer le lien pour réinitialiser le mot de passe"
#: lib/claper_web/live/embed_live/form_component.html.heex:38
#, elixir-autogen, elixir-format
msgid "Attendee can view the web content on their device"
msgstr "Le participant peut voir le contenu web sur son appareil"
#: lib/claper_web/live/event_live/embed_component.ex:59
#, elixir-autogen, elixir-format, fuzzy
msgid "Current web content"
msgstr "Contenu web actuel"
#: lib/claper_web/live/event_live/manage.html.heex:335
#, elixir-autogen, elixir-format
msgid "Edit web content"
msgstr "Modifier le contenu web"
#: lib/claper_web/live/event_live/manage.html.heex:334
#, elixir-autogen, elixir-format
msgid "New web content"
msgstr "Nouveau contenu web"
#: lib/claper_web/live/event_live/embed_component.ex:36
#, elixir-autogen, elixir-format, fuzzy
msgid "See current web content"
msgstr "Voir le contenu web actuel"
#: lib/claper_web/live/embed_live/form_component.html.heex:25
#, elixir-autogen, elixir-format
msgid "The iframe component"
msgstr "Le composant iframe"
#: lib/claper_web/live/embed_live/form_component.html.heex:62
#, elixir-autogen, elixir-format, fuzzy
msgid "This will delete the web content, are you sure?"
msgstr "Cela supprimera le contenu web, êtes-vous sûr?"
#: lib/claper_web/live/embed_live/form_component.html.heex:14
#, elixir-autogen, elixir-format
msgid "Title"
msgstr "Titre"
#: lib/claper_web/live/event_live/manage.html.heex:248
#: lib/claper_web/live/event_live/manage.html.heex:618
#: lib/claper_web/live/stat_live/index.html.heex:257
#, elixir-autogen, elixir-format
msgid "Web content"
msgstr "Contenu web"
#: lib/claper/embeds/embed.ex:38
#, elixir-autogen, elixir-format, fuzzy
msgid "Invalid embed format (should start with <iframe> and end with </iframe>)"
msgstr "Format d'intégration invalide (doit commencer par <iframe> et se terminer par </iframe>)"
#: lib/claper_web/live/event_live/manage.html.heex:781
#: lib/claper_web/live/event_live/manage.html.heex:810
#: lib/claper_web/live/event_live/manage.html.heex:956
#: lib/claper_web/live/event_live/manage.html.heex:985
#, elixir-autogen, elixir-format
msgid "Pin"
msgstr "Épingler"
#: lib/claper_web/live/event_live/post_component.ex:59
#: lib/claper_web/live/event_live/post_component.ex:175
#, elixir-autogen, elixir-format
msgid "Pinned"
msgstr "Épinglé"
#: lib/claper_web/live/event_live/manage.html.heex:714
#, elixir-autogen, elixir-format, fuzzy
msgid "Pinned messages"
msgstr "Messages épinglés"
#: lib/claper_web/live/event_live/manage.html.heex:925
#, elixir-autogen, elixir-format
msgid "Pinned messages will appear here."
msgstr "Les messages épinglés apparaîtront ici."
#: lib/claper_web/live/event_live/manage.html.heex:1198
#, elixir-autogen, elixir-format
msgid "Show only pinned messages"
msgstr "Afficher uniquement les messages épinglés"
#: lib/claper_web/live/event_live/manage.html.heex:779
#: lib/claper_web/live/event_live/manage.html.heex:808
#: lib/claper_web/live/event_live/manage.html.heex:954
#: lib/claper_web/live/event_live/manage.html.heex:983
#, elixir-autogen, elixir-format
msgid "Unpin"
msgstr "Détacher"
#: lib/claper_web/templates/leader_notifier/invitation.html.heex:35
#, elixir-autogen, elixir-format
msgid "Login or create account"
msgstr "Connectez-vous ou créez un compte"
#: lib/claper_web/templates/leader_notifier/invitation.html.heex:22
#, elixir-autogen, elixir-format
msgid "Someone invited you to manage the event: %{name}"
msgstr "Quelqu'un vous a invité à gérer l'événement : %{name}"
#: lib/claper_web/templates/leader_notifier/invitation.html.heex:25
#, elixir-autogen, elixir-format
msgid "To accept the invitation, please login or create an account with this email: %{email}"
msgstr "Pour accepter l'invitation, veuillez vous connecter ou créer un compte avec cette adresse e-mail : %{email}"
#: lib/claper_web/templates/leader_notifier/invitation.html.heex:17
#, elixir-autogen, elixir-format
msgid "You have been invited"
msgstr "Vous avez été invité"
#: lib/claper_web/notifiers/leader_notifier.ex:12
#, elixir-autogen, elixir-format
msgid "You have been invited to manage an event"
msgstr "Vous avez été invité à gérer un événement"
#: lib/claper_web/live/event_live/form_component.ex:103
#, elixir-autogen, elixir-format, fuzzy
msgid "Saved"
msgstr "Enregistré"

View File

@@ -0,0 +1,13 @@
defmodule Claper.Repo.Migrations.AddPinnedToPostsAndPresentationStates do
use Ecto.Migration
def change do
alter table(:presentation_states) do
add :show_only_pinned, :boolean, default: false
end
alter table(:posts) do
add :pinned, :boolean, default: false
end
end
end

View File

@@ -0,0 +1,16 @@
defmodule Claper.Repo.Migrations.CreateEmbeds do
use Ecto.Migration
def change do
create table(:embeds) do
add :title, :string, null: false
add :content, :text, null: false
add :position, :integer, default: 0
add :enabled, :boolean, default: true
add :attendee_visibility, :boolean, default: false
add :presentation_file_id, references(:presentation_files, on_delete: :nilify_all)
timestamps()
end
end
end

View File

@@ -0,0 +1,99 @@
defmodule Claper.EmbedsTest do
use Claper.DataCase
alias Claper.Embeds
describe "embeds" do
alias Claper.Embeds.Embed
import Claper.{EmbedsFixtures, PresentationsFixtures}
@invalid_attrs %{title: nil, content: nil}
test "list_embeds/1 returns all embeds from a presentation" do
presentation_file = presentation_file_fixture()
embed = embed_fixture(%{presentation_file_id: presentation_file.id})
assert Embeds.list_embeds(presentation_file.id) == [embed]
end
test "list_embeds_at_position/2 returns all embeds from a presentation at a given position" do
presentation_file = presentation_file_fixture()
embed = embed_fixture(%{presentation_file_id: presentation_file.id, position: 5})
assert Embeds.list_embeds_at_position(presentation_file.id, 5) == [embed]
end
test "get_embed!/1 returns the embed with given id" do
presentation_file = presentation_file_fixture()
embed = embed_fixture(%{presentation_file_id: presentation_file.id})
assert Embeds.get_embed!(embed.id) == embed
end
test "create_embed/1 with valid data creates a embed" do
presentation_file = presentation_file_fixture()
valid_attrs = %{
title: "some title",
content:
"<iframe src=\"https://www.youtube.com/embed/9bZkp7q19f0\" frameborder=\"0\" allowfullscreen></iframe>",
presentation_file_id: presentation_file.id,
position: 0
}
assert {:ok, %Embed{} = embed} = Embeds.create_embed(valid_attrs)
assert embed.title == "some title"
assert embed.content ==
"<iframe src=\"https://www.youtube.com/embed/9bZkp7q19f0\" frameborder=\"0\" allowfullscreen></iframe>"
end
test "create_embed/1 with invalid data returns error changeset" do
assert {:error, %Ecto.Changeset{}} = Embeds.create_embed(@invalid_attrs)
end
test "update_embed/3 with valid data updates the embed" do
presentation_file = presentation_file_fixture()
embed = embed_fixture(%{presentation_file_id: presentation_file.id})
update_attrs = %{
title: "some updated title",
content:
"<iframe src=\"https://www.youtube.com/embed/9bZkp7q19f0\" frameborder=\"0\"></iframe>"
}
assert {:ok, %Embed{} = embed} =
Embeds.update_embed(presentation_file.event_id, embed, update_attrs)
assert embed.title == "some updated title"
assert embed.content ==
"<iframe src=\"https://www.youtube.com/embed/9bZkp7q19f0\" frameborder=\"0\"></iframe>"
end
test "update_embed/3 with invalid data returns error changeset" do
presentation_file = presentation_file_fixture()
embed = embed_fixture(%{presentation_file_id: presentation_file.id})
assert {:error, %Ecto.Changeset{}} =
Embeds.update_embed(presentation_file.event_id, embed, @invalid_attrs)
assert embed == Embeds.get_embed!(embed.id)
end
test "delete_embed/2 deletes the embed" do
presentation_file = presentation_file_fixture()
embed = embed_fixture(%{presentation_file_id: presentation_file.id})
assert {:ok, %Embed{}} = Embeds.delete_embed(presentation_file.event_id, embed)
assert_raise Ecto.NoResultsError, fn -> Embeds.get_embed!(embed.id) end
end
test "change_embed/1 returns a embed changeset" do
presentation_file = presentation_file_fixture()
embed = embed_fixture(%{presentation_file_id: presentation_file.id})
assert %Ecto.Changeset{} = Embeds.change_embed(embed)
end
end
end

View File

@@ -0,0 +1,27 @@
defmodule Claper.EmbedsFixtures do
@moduledoc """
This module defines test helpers for creating
entities via the `Claper.Embeds` context.
"""
require Claper.UtilFixture
@doc """
Generate a embed.
"""
def embed_fixture(attrs \\ %{}, preload \\ []) do
{:ok, embed} =
attrs
|> Enum.into(%{
title: "some title",
content:
"<iframe src=\"https://www.youtube.com/embed/9bZkp7q19f0\" frameborder=\"0\" allowfullscreen></iframe>",
position: 0,
enabled: true,
attendee_visibility: true
})
|> Claper.Embeds.create_embed()
Claper.UtilFixture.merge_preload(embed, preload, %{})
end
end