Skip to content

Commit

Permalink
Merge branch 'release/0.19.1'
Browse files Browse the repository at this point in the history
  • Loading branch information
“Apoorv committed Jul 31, 2023
2 parents 45f67a4 + 5b7bf83 commit d353d54
Show file tree
Hide file tree
Showing 59 changed files with 1,993 additions and 143 deletions.
22 changes: 20 additions & 2 deletions app/controllers/internal_api/v1/clients_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,12 @@ def create
def show
authorize client

render json: {
render locals: {
client_details: Client::ShowPresenter.new(client).process,
project_details: client.project_details(params[:time_frame]),
total_minutes: client.total_hours_logged(params[:time_frame]),
overdue_outstanding_amount: client.client_overdue_and_outstanding_calculation
overdue_outstanding_amount: client.client_overdue_and_outstanding_calculation,
invoices: client.invoices
},
status: :ok
end
Expand Down Expand Up @@ -68,6 +69,19 @@ def destroy
end
end

def send_payment_reminder
authorize client

SendPaymentReminderMailer.with(
recipients: client_email_params[:email_params][:recipients],
selected_invoices: client_email_params[:selected_invoices],
message: client_email_params[:email_params][:message],
subject: client_email_params[:email_params][:subject],
).send_payment_reminder.deliver_later

render json: { notice: "Payment reminder has been sent to #{client.email}" }, status: :accepted
end

private

def client
Expand All @@ -90,4 +104,8 @@ def update_client_params
client_params
end
end

def client_email_params
params.require(:client_email).permit(email_params: [:subject, :message, recipients: []], selected_invoices: [])
end
end
8 changes: 1 addition & 7 deletions app/controllers/internal_api/v1/employments_controller.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# frozen_string_literal: true

class InternalApi::V1::EmploymentsController < InternalApi::V1::ApplicationController
before_action :set_user, only: [:show]
before_action :set_employment, only: [:update, :show]

def index
Expand All @@ -11,8 +10,7 @@ def index

def show
authorize @employment
employment_with_email = @employment.attributes.merge(email: @user.email)
render json: { employment: employment_with_email }, status: :ok
render :show
end

def update
Expand All @@ -23,10 +21,6 @@ def update

private

def set_user
@user ||= User.find(params[:id])
end

def set_employment
@employment = Employment.find_by!(user_id: params[:id], company_id: current_company.id)
end
Expand Down
13 changes: 12 additions & 1 deletion app/controllers/internal_api/v1/team_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,18 @@ def index
.ransack(first_name_or_last_name_or_recipient_email_cont: params.dig(:q, :first_name_or_last_name_or_email_cont))
teams = query.result(distinct: true)
invitations = invitations_query.result(distinct: true)
render :index, locals: TeamPresenter.new(teams, invitations, current_user, current_company).index_data, status: :ok

presenter_data = TeamPresenter.new(teams, invitations, current_user, current_company).index_data
team_data = presenter_data[:teams]
invitation_data = presenter_data[:invitations]

combined_data = team_data + invitation_data
pagy_combined, combined_details = pagy_array(combined_data, items: params[:items] || 10)

render :index, locals: {
combined_details:,
pagination_details_combined: pagy_metadata(pagy_combined)
}, status: :ok
end

def update
Expand Down
13 changes: 12 additions & 1 deletion app/javascript/src/apis/clients.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,20 @@ const update = async (id, payload) => axios.patch(`${path}/${id}`, payload);

const destroy = async id => axios.delete(`${path}/${id}`);

const sendPaymentReminder = async (id, payload) =>
axios.post(`${path}/${id}/send_payment_reminder`, payload);

const invoices = async (query = "") =>
axios.get(query ? `${path}/invoices?${query}` : `${path}/invoices`);

const clientApi = { update, destroy, get, show, create, invoices };
const clientApi = {
update,
destroy,
get,
show,
create,
invoices,
sendPaymentReminder,
};

export default clientApi;
2 changes: 1 addition & 1 deletion app/javascript/src/apis/team.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import axios from "./api";

const path = "/team";

const get = () => axios.get(path);
const get = (query = "") => axios.get(query ? `${path}?${query}` : path);
const search = term => {
const payload = { "q[first_name_or_last_name_or_email_cont]": term };
const queryParams = new URLSearchParams(payload).toString();
Expand Down
59 changes: 35 additions & 24 deletions app/javascript/src/common/ChartBar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@ const Client = ({ element, totalMinutes, index }: ISingleClient) => {
const chartColorIndex = index % 4;
const randomColor = chartColor[chartColorIndex];
const hourPercentage = (element.minutes * 100) / totalMinutes;
const finalHourPercentage =
hourPercentage > 1 ? hourPercentage : Math.ceil(hourPercentage);

const divStyle = {
width: `${hourPercentage}%`,
width: `${finalHourPercentage}%`,
};

return (
Expand All @@ -41,29 +43,38 @@ const Client = ({ element, totalMinutes, index }: ISingleClient) => {
);
};

const GetClientBar = ({ data, totalMinutes }: IChartBarGraph) => (
<section>
<div className="hidden md:block">
<p className="mb-3 text-tiny tracking-widest text-miru-dark-purple-600">
TOTAL HOURS:{" "}
<span className="font-medium">{minToHHMM(totalMinutes)}</span>
</p>
<div className="flex h-1 w-full bg-gray-200">
{data.map((element, index) => (
<Client
element={element}
index={index}
key={index}
totalMinutes={totalMinutes}
/>
))}
</div>
<div className="mt-3 flex justify-between pb-6 text-tiny tracking-widest text-miru-dark-purple-400">
<span>0</span>
<span>{minToHHMM(totalMinutes)}</span>
const GetClientBar = ({ data, totalMinutes }: IChartBarGraph) => {
//removing elements whose minutes value is less than or equal to zero.
const dataWithMinutes = data.filter(element => element.minutes > 0);

return (
<section>
<div className="hidden md:block">
<p className="mb-3 text-tiny tracking-widest text-miru-dark-purple-600">
TOTAL HOURS:{" "}
<span className="font-medium">{minToHHMM(totalMinutes)}</span>
</p>
<div className="flex h-1 w-full bg-gray-200">
{dataWithMinutes.map((element, index) => {
if (element.minutes > 0) {
return (
<Client
element={element}
index={index}
key={index}
totalMinutes={totalMinutes}
/>
);
}
})}
</div>
<div className="mt-3 flex justify-between pb-6 text-tiny tracking-widest text-miru-dark-purple-400">
<span>0</span>
<span>{minToHHMM(totalMinutes)}</span>
</div>
</div>
</div>
</section>
);
</section>
);
};

export default GetClientBar;
3 changes: 3 additions & 0 deletions app/javascript/src/common/CustomTextareaAutosize.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export const CustomTextareaAutosize = ({
wrapperClassName,
rows,
maxRows,
maxLength,
}) => {
const inputRef = useRef(null);
const [focused, setFocused] = useState<boolean>(false);
Expand All @@ -42,6 +43,7 @@ export const CustomTextareaAutosize = ({
className={inputBoxClassName}
cols={60}
id={id}
maxLength={maxLength}
maxRows={maxRows}
name={name}
placeholder=" "
Expand All @@ -58,4 +60,5 @@ CustomTextareaAutosize.defaultProps = {
inputBoxClassName:
"form__input block w-full appearance-none bg-white p-4 text-sm lg:text-base h-16 border-miru-gray-1000",
wrapperClassName: "outline relative",
maxLength: 100000000,
};
42 changes: 31 additions & 11 deletions app/javascript/src/common/Pagination/Pagination.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type Pagination = {
setParams: any;
handleClick?: any;
isReport?: boolean;
isTeamPage?: boolean;
};

const Pagination = ({
Expand All @@ -23,11 +24,12 @@ const Pagination = ({
title,
handleClick,
isReport = false,
isTeamPage = false,
}: Pagination) => {
const { isDesktop } = useUserContext();

const currentPage = params.page;
const totalPageCount = pagy.pages;
const currentPage = params?.page;
const totalPageCount = pagy?.pages;
const siblingCount = 1;

const paginationRange = usePagination({
Expand All @@ -50,20 +52,40 @@ const Pagination = ({
return pagy?.last == currentPage;
};

const isNotFirstPage = () => {
if (typeof pagy?.first == "boolean") {
return !pagy?.first;
}

return pagy?.page > 1;
};

const handleOnClick = e => {
if (isTeamPage) {
handleClick(Number(1), Number(e.target.value));
setParams({ ...params, items: Number(e.target.value) });
} else {
setParams({
page: 1,
invoices_per_page: Number(e.target.value),
});
}
};

return (
<div className="bg-grey-400 relative flex w-full items-center px-0 pt-5 pb-20 md:pb-28 lg:py-10 lg:pl-36">
<div className="mx-auto w-full">
{pagy?.pages > 1 && (
<div className="flex items-center justify-center">
{!pagy?.first && (
{isNotFirstPage() && (
<button
disabled={pagy?.first}
className={cn("m-1 mx-4 font-bold", {
"text-miru-gray-400": pagy?.first,
"text-miru-han-purple-1000": !pagy?.first,
"text-miru-han-purple-1000": isNotFirstPage(),
})}
onClick={() => {
isReport
isReport || isTeamPage
? handleClick(pagy?.prev)
: setParams({ ...params, page: pagy?.prev });
}}
Expand All @@ -84,7 +106,7 @@ const Pagination = ({
}
)}
onClick={() => {
isReport
isReport || isTeamPage
? handleClick(page)
: handlePageNumberClick(page);
}}
Expand All @@ -102,7 +124,7 @@ const Pagination = ({
"text-miru-han-purple-1000": !isLastPage(),
})}
onClick={() => {
isReport
isReport || isTeamPage
? handleClick(pagy?.next)
: setParams({ ...params, page: pagy?.next });
}}
Expand All @@ -118,10 +140,8 @@ const Pagination = ({
<select
className="p-2 text-xs font-bold text-miru-han-purple-1000"
defaultValue={pagy?.items}
value={params.invoices_per_page}
onChange={e =>
setParams({ page: 1, invoices_per_page: Number(e.target.value) })
}
value={isTeamPage ? params?.items : params.invoices_per_page}
onChange={handleOnClick}
>
<option value="10">10</option>
<option value="20">20</option>
Expand Down
24 changes: 23 additions & 1 deletion app/javascript/src/components/Clients/Details/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
PlusIcon,
EditIcon,
InfoIcon,
ReminderIcon,
} from "miruIcons";
import { useNavigate } from "react-router-dom";
import { MobileMoreOptions, Modal } from "StyledComponents";
Expand All @@ -19,7 +20,12 @@ import { useUserContext } from "context/UserContext";
import DeleteClient from "../Modals/DeleteClient";
import EditClient from "../Modals/EditClient";

const Header = ({ clientDetails, setShowProjectModal, fetchDetails }) => {
const Header = ({
clientDetails,
setShowProjectModal,
fetchDetails,
setSendPaymentReminder,
}) => {
const [isHeaderMenuVisible, setIsHeaderMenuVisible] =
useState<boolean>(false);
const [isClientOpen, setIsClientOpen] = useState<boolean>(false);
Expand Down Expand Up @@ -104,6 +110,12 @@ const Header = ({ clientDetails, setShowProjectModal, fetchDetails }) => {
<span className="ml-3">Edit</span>
</button>
</li>
<li onClick={() => setSendPaymentReminder(true)}>
<button className="menuButton__list-item">
<ReminderIcon id="reminderIcon" size={16} />
<span className="ml-3">Payment Reminder</span>
</button>
</li>
<li onClick={handleDelete}>
<button className="menuButton__list-item text-miru-red-400">
<DeleteIcon color="#E04646" size={16} weight="bold" />
Expand Down Expand Up @@ -172,6 +184,16 @@ const Header = ({ clientDetails, setShowProjectModal, fetchDetails }) => {
<PlusIcon />
<span className="ml-3">Add new project</span>
</li>
<li
className="menuButton__list-item px-0"
onClick={() => {
setSendPaymentReminder(true);
setShowMobileModal(false);
}}
>
<ReminderIcon id="reminderIcon" size={16} />
<span className="ml-3">Payment Reminder</span>
</li>
<li
className="menuButton__list-item px-0"
onClick={() => {
Expand Down
Loading

0 comments on commit d353d54

Please sign in to comment.