Skip to content
This repository was archived by the owner on Apr 24, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions assets/css/app.css
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,13 @@
--time-tracking-container-bg: 255, 255, 255;

--activity-list-bg: 241, 243, 244;
--time-tracker-start-btn-bg: 124, 196, 108;
--time-tracker-start-btn-active-txt: 255, 255, 255;
--time-tracker-start-btn-active-bg: 124, 196, 108;
--time-tracker-countdown-btn-bg: 68, 108, 60;
--time-tracker-dropdown-border: 203, 201, 210;
--time-tracker-start-btn-disabled-bg: 232, 232, 232;
--time-tracker-start-btn-disabled-txt: 157, 157, 157;
}

/* dark mode colors */
Expand Down Expand Up @@ -83,6 +90,12 @@
--time-tracking-container-bg: 255, 255, 255;

--activity-list-bg: 241, 243, 244;
--time-tracker-start-btn-bg: 124, 196, 108;
--time-tracker-start-btn-txt: 255, 255, 255;
--time-tracker-countdown-btn-bg: 68, 108, 60;
--time-tracker-dropdown-border: 203, 201, 210;
--time-tracker-start-btn-disabled-bg: 232, 232, 232;
--time-tracker-start-btn-disabled-txt: 157, 157, 157;
}

/* This file is for your main application CSS */
Expand Down Expand Up @@ -121,6 +134,32 @@ table:has(#activities) #activities > tr:last-child > td:has(.position) .position
@apply relative w-full;
}

.time-tracking-form-grid {
position: relative;
display: grid;
gap: .5em;
grid-template-columns: repeat(2, 1fr);
grid-template-areas:
"activity-prompt activity-prompt"
"btn btn";
}

.time-tracking-form-grid > .activity-btn {
grid-area: activity-prompt;
}

.time-tracking-form-grid > .project-btn {
grid-area: project-prompt;
}

.time-tracking-form-grid > button {
grid-area: btn;
}

.time-tracking-form-grid .prompt-text {
@apply line-clamp-1;
}

.wrap-collapsible {
display: grid;
grid-template-columns: .45em .10em 1em 1fr;
Expand Down
1 change: 1 addition & 0 deletions assets/js/hooks/drop_down_input.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export default DropDownInput = {
dropdownPrompt.classList.toggle("border-form-input-border")
dropdownPrompt.classList.toggle("border-form-border-focus")
dropdownPrompt.querySelector(".hero-chevron-down").classList.toggle("rotate-180")
dropdownOptionsContainer.style.display = "unset"
})

// Item selection
Expand Down
2 changes: 0 additions & 2 deletions assets/js/hooks/search_activity_input.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ export default SearchActivityInput = {
const activitiesList = document.querySelector("#activities-list")
const searchActivitiesList = document.querySelector("#search-activities-list-container")

console.log(searchActivitiesList)

searchInputField.addEventListener("input", (event) => {
let searchQuery = event.target.value.trim()
if (searchQuery !== "") {
Expand Down
7 changes: 7 additions & 0 deletions assets/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,13 @@ module.exports = {
"time-tracking-container-shadow": "rgba(var(--time-tracking-container-shadow))",
"time-tracking-container-bg": "rgba(var(--time-tracking-container-bg))",
"activity-list-bg": "rgba(var(--activity-list-bg))",
"time-tracker-start-btn-bg": "rgba(var(--time-tracker-start-btn-bg))",
"time-tracker-countdown-btn-bg": "rgba(var(--time-tracker-countdown-btn-bg))",
"time-tracker-dropdown-border": "rgba(var(--time-tracker-dropdown-border))",
"time-tracker-start-btn-disabled-bg": "rgba(var(--time-tracker-start-btn-disabled-bg))",
"time-tracker-start-btn-disabled-txt": "rgba(var(--time-tracker-start-btn-disabled-txt))",
"time-tracker-start-btn-active-bg": "rgba(var(--time-tracker-start-btn-active-bg))",
"time-tracker-start-btn-active-txt": "rgba(var(--time-tracker-start-btn-active-txt))",
},
fontFamily: {
openSans: ["Open Sans", "serif"],
Expand Down
10 changes: 8 additions & 2 deletions lib/omedis_web/components/client_doctor_form_components.ex
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ defmodule OmedisWeb.ClientDoctorFormComponents do
attr :dropdown_options, :list, doc: "the options for dropdown inputs"
attr :dropdown_prompt, :string, doc: "the prompt for dropdown inputs"
attr :dropdown_search_prompt, :string, doc: "the prompt for search inputs", default: "Search"
attr :dropdown_list_class, :string, default: nil
attr :dropdown_prompt_class, :string, default: nil

attr :has_dropdown_slot, :boolean,
default: false,
Expand Down Expand Up @@ -102,7 +104,10 @@ defmodule OmedisWeb.ClientDoctorFormComponents do
<input type="hidden" name={@name} id={@id} value={@value} />

<button
class="text-form-txt-primary flex items-center justify-between w-full py-2 border-b-[1px] border-form-input-border mb-1"
class={[
"text-form-txt-primary flex items-center justify-between w-full p-2 border-b-[1px] border-form-input-border mb-1",
@dropdown_prompt_class
]}
type="button"
id={"dropdown-prompt-#{@id}"}
phx-update="ignore"
Expand Down Expand Up @@ -142,7 +147,8 @@ defmodule OmedisWeb.ClientDoctorFormComponents do
<ul
class={[
"grid gap-y-2 max-h-[20em] overflow-y-scroll dropdown-options-list",
@dropdown_searchable && "mt-2"
@dropdown_searchable && "mt-2",
@dropdown_list_class
]}
id={"dropdown-options-list-#{@id}"}
role="listbox"
Expand Down
2 changes: 1 addition & 1 deletion lib/omedis_web/components/custom_components.ex
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ defmodule OmedisWeb.CustomComponents do
~H"""
<div
class={[
"font-openSans w-[90%] absolute right-2 -translate-x-2 top-[80%] hidden",
"font-openSans w-[90%] absolute right-2 -translate-x-2 top-[80%] z-[10000] hidden",
"border-[1px] border-time-tracking-container-border rounded-lg pt-6 bg-time-tracking-container-bg shadow-sm shadow-time-tracking-container-shadow"
]}
id="time-tracking-component"
Expand Down
114 changes: 113 additions & 1 deletion lib/omedis_web/live/playground_live/time_tracking.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ defmodule OmedisWeb.PlaygroundLive.TimeTracking do

import OmedisWeb.CustomComponents

alias OmedisWeb.ClientDoctorFormComponents

@impl Phoenix.LiveView
def mount(_params, _session, socket) do
favourite_activities = [
Expand Down Expand Up @@ -53,11 +55,19 @@ defmodule OmedisWeb.PlaygroundLive.TimeTracking do
}
]

projects = for i <- 1..10, do: "Project #{i}"

fields = %{"activity" => "", "project" => ""}

{:ok,
socket
|> assign(:activities, activities)
|> assign(:favourite_activities, favourite_activities)
|> assign(:search_activities, [])}
|> assign(:form, to_form(fields))
|> assign(:projects, projects)
|> assign(:search_activities, [])
|> assign(:begin_countdown, false)
|> assign(:elapsed_time, "00:00:00")}
end

@impl Phoenix.LiveView
Expand All @@ -66,6 +76,21 @@ defmodule OmedisWeb.PlaygroundLive.TimeTracking do
{:noreply, assign(socket, :search_activities, search_activities)}
end

def handle_event("validate", params, socket) do
{:noreply, assign(socket, :form, to_form(params))}
end

def handle_event("save", params, socket) do
{:noreply,
socket
|> assign(:form, to_form(params))
|> assign(:begin_countdown, true)}
end

def handle_event("stop-countdown", _params, socket) do
{:noreply, assign(socket, :begin_countdown, false)}
end

defp search_activities(activity_query, socket) do
Enum.filter(
socket.assigns.activities,
Expand All @@ -86,7 +111,94 @@ defmodule OmedisWeb.PlaygroundLive.TimeTracking do
favourite_activities={@favourite_activities}
search_activities={@search_activities}
/>

<.form
for={@form}
phx-change="validate"
phx-submit="save"
class="text-sm time-tracking-form-grid px-2 py-4"
>
<ClientDoctorFormComponents.custom_input
type="dropdown"
field={@form[:project]}
id="project-list"
dropdown_prompt="Select project"
dropdown_options={
Enum.map(@projects, fn project ->
Phoenix.HTML.raw(~s"
<span class='px-4'>#{project}</span>
")
end)
}
dropdown_prompt_class="project-btn text-sm"
dropdown_list_class="absolute inset-x-[0.5rem] bg-white shadow-md rounded-lg border-[1px] border-time-tracker-dropdown-border z-[10000]"
/>

<ClientDoctorFormComponents.custom_input
type="dropdown"
field={@form[:activity]}
id="activity-list"
dropdown_prompt="Select activity"
dropdown_options={
Enum.map(@activities, fn activity ->
Phoenix.HTML.raw(~s"
<span class='flex items-center gap-2 px-4'>
<span>#{activity_color_icon(activity)}</span>
<span>#{activity.title}</span>
</span>
")
end)
}
has_dropdown_slot={true}
dropdown_prompt_class="activity-btn text-sm"
dropdown_list_class="absolute inset-x-[0.5rem] bg-white shadow-md rounded-lg border-[1px] border-time-tracker-dropdown-border z-[10000]"
/>

<button
:if={!@begin_countdown}
type="submit"
class={[
"btn px-4 py-2 rounded-md text-base mt-2",
(input_value(@form, :project) == "" || input_value(@form, :activity) == "") &&
"bg-time-tracker-start-btn-disabled-bg text-time-tracker-start-btn-disabled-txt cursor-not-allowed",
input_value(@form, :project) != "" && input_value(@form, :activity) != "" &&
"bg-time-tracker-start-btn-bg text-white cursor-pointer"
]}
disabled={input_value(@form, :project) == "" || input_value(@form, :activity) == ""}
title={
if input_value(@form, :project) == "" || input_value(@form, :activity) == "",
do: "Please select a project and activity"
}
>
<span>
Start timer <.icon name="hero-play-circle-solid" class="w-5 h-5" />
</span>
</button>

<button
:if={@begin_countdown}
type="button"
class="btn px-4 py-2 mt-2 rounded-md text-base bg-time-tracker-countdown-btn-bg text-white cursor-pointer flex items-center justify-center gap-2"
phx-click="stop-countdown"
>
<span class="h-4 w-4 bg-time-tracker-start-btn-bg rounded-full inline-block border-[2px] border-white animate-pulse">
</span>
<span>{@elapsed_time}</span>
<.icon name="hero-stop-circle-solid" class="w-5 h-5" />
</button>
</.form>
</section>
"""
end

defp activity_color_icon(activity) do
~s"""
<svg width='20' height='20' viewBox='0 0 20 20' fill='none' xmlns='http://www.w3.org/2000/svg'>
<path d='M20 10C20 15.5228 15.5228 20 10 20C4.47715 20 0 15.5228 0 10C0 4.47715 4.47715 0 10 0C15.5228 0 20 4.47715 20 10ZM1.9775 10C1.9775 14.4307 5.5693 18.0225 10 18.0225C14.4307 18.0225 18.0225 14.4307 18.0225 10C18.0225 5.5693 14.4307 1.9775 10 1.9775C5.5693 1.9775 1.9775 5.5693 1.9775 10Z'
fill='#{activity.color}'
/>
<circle cx='10' cy='10' r='3' fill='#{activity.color}' />
</svg>
"""
end
end