Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expense module remaining work #1706

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,7 @@ PLATFORMS
arm64-darwin-22
x86_64-darwin-21
x86_64-darwin-22
x86_64-darwin-23
Shruti-Apte marked this conversation as resolved.
Show resolved Hide resolved
x86_64-linux

DEPENDENCIES
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/internal_api/v1/expenses_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def destroy

def expense_params
params.require(:expense).permit(
:amount, :date, :description, :expense_type, :expense_category_id, :vendor_id, :receipts
:amount, :date, :description, :expense_type, :expense_category_id, :vendor_id, receipts: []
)
end

Expand Down
1 change: 0 additions & 1 deletion app/javascript/src/StyledComponents/Pagination/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,6 @@ const Pagination = ({
<div className="flex items-center justify-end">
<select
className="p-2 text-xs font-bold text-miru-han-purple-1000"
defaultValue={itemsPerPage}
value={itemsPerPage}
onChange={handleClickOnPerPage}
>
Expand Down
12 changes: 10 additions & 2 deletions app/javascript/src/apis/expenses.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@ import axios from "./api";

const path = "/expenses";

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

const create = async payload => await axios.post(path, payload);
const create = async payload =>
Shruti-Apte marked this conversation as resolved.
Show resolved Hide resolved
await axios.post(path, payload, {
headers: {
"Content-Type": "multipart/form-data",
},
});

const show = async id => await axios.get(`${path}/${id}`);

Expand All @@ -15,13 +20,16 @@ const destroy = async id => axios.delete(`${path}/${id}`);
const createCategory = async payload =>
axios.post("/expense_categories", payload);

const createVendors = async payload => axios.post("/vendors", payload);

const expensesApi = {
index,
create,
show,
update,
destroy,
createCategory,
createVendors,
};

export default expensesApi;
6 changes: 6 additions & 0 deletions app/javascript/src/common/AutoSearch/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const AutoSearch = ({
searchAction,
SearchDataRow,
wrapperClassName,
handleEnter,
clearSearch,
}: Iprops) => {
const [searchQuery, setSearchQuery] = useState<string>("");
const [searchResult, setSearchResult] = useState<any[]>([]);
Expand All @@ -36,6 +38,7 @@ const AutoSearch = ({

const onSearchClear = () => {
setSearchQuery("");
clearSearch();
};

return (
Expand All @@ -47,6 +50,7 @@ const AutoSearch = ({
type="text"
value={searchQuery}
onChange={e => setSearchQuery(e.target.value)}
onKeyDown={e => handleEnter(debouncedSearchQuery, e.key === "Enter")}
/>
<button className=" absolute inset-y-0 right-3 flex cursor-pointer items-center pr-3 ">
{searchQuery ? (
Expand All @@ -68,6 +72,8 @@ interface Iprops {
searchAction: (val) => any; // eslint-disable-line
SearchDataRow;
wrapperClassName?: string;
handleEnter?: (val, shouldUpdate) => any; // eslint-disable-line
clearSearch?: () => any;
}

export default AutoSearch;
17 changes: 14 additions & 3 deletions app/javascript/src/components/Expenses/Details/Expense.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import React from "react";

import { currencyFormat } from "helpers";

import { FileDownloader } from "../utils";

const Expense = ({ expense, currency }) => (
<div className="mt-8 flex flex-col px-4 lg:px-0">
<div className="flex flex-col">
Expand Down Expand Up @@ -41,9 +43,18 @@ const Expense = ({ expense, currency }) => (
<span className="text-xs font-medium text-miru-dark-purple-1000">
Receipt
</span>
<span className="text-base font-medium text-miru-dark-purple-1000">
{expense?.receipt || "-"}
</span>
<div className="flex flex-col">
{expense?.receipts.length > 0
? expense?.receipts.map((receipt, index) => (
<span
className="my-2 cursor-pointer text-base font-medium text-miru-dark-purple-1000 underline"
key={index}
>
<FileDownloader fileUrl={receipt} />
</span>
))
: "-"}
</div>
</div>
</div>
<div className="flex flex-col">
Expand Down
73 changes: 41 additions & 32 deletions app/javascript/src/components/Expenses/Details/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Logger from "js-logger";
import { useNavigate, useParams } from "react-router-dom";

import expensesApi from "apis/expenses";
import Loader from "common/Loader/index";
import { useUserContext } from "context/UserContext";

import Expense from "./Expense";
Expand All @@ -21,6 +22,7 @@ const ExpenseDetails = () => {
const [showEditExpenseModal, setShowEditExpenseModal] =
useState<boolean>(false);
const [expense, setExpense] = useState<any>();
const [isLoading, setIsLoading] = useState<boolean>(true);
const [expenseData, setExpenseData] = useState<any>();

const params = useParams();
Expand All @@ -36,6 +38,7 @@ const ExpenseDetails = () => {
setVendorData(res.data.vendors);
setExpenseData(res.data);
setExpense(resData.data);
setIsLoading(false);
} catch (e) {
Logger.error(e);
navigate("/expenses");
Expand Down Expand Up @@ -80,41 +83,47 @@ const ExpenseDetails = () => {
}, []);

return (
<div>
{!isDesktop && showEditExpenseModal ? null : (
<div className="h-full">
{isLoading ? (
Shruti-Apte marked this conversation as resolved.
Show resolved Hide resolved
<Loader />
) : (
<div>
<Header
expense={expense}
handleDelete={handleDelete}
handleEdit={handleEdit}
/>
<Expense currency={company.base_currency} expense={expense} />
{!isDesktop && showEditExpenseModal ? null : (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use && and remove null by altering condition

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this can not be refactored, If we use the altering condition, it breaks on mobile view.
Returning null is necessary here.

<div>
<Header
expense={expense}
handleDelete={handleDelete}
handleEdit={handleEdit}
/>
<Expense currency={company.base_currency} expense={expense} />
</div>
)}
{showEditExpenseModal &&
(isDesktop ? (
<EditExpenseModal
expense={expense}
expenseData={expenseData}
handleEditExpense={handleEditExpense}
setShowEditExpenseModal={setShowEditExpenseModal}
showEditExpenseModal={showEditExpenseModal}
/>
) : (
<EditExpense
expense={expense}
expenseData={expenseData}
handleEditExpense={handleEditExpense}
setShowEditExpenseModal={setShowEditExpenseModal}
/>
))}
{showDeleteExpenseModal && (
<DeleteExpenseModal
handleDeleteExpense={handleDeleteExpense}
setShowDeleteExpenseModal={setShowDeleteExpenseModal}
showDeleteExpenseModal={showDeleteExpenseModal}
/>
)}
</div>
)}
{showEditExpenseModal &&
(isDesktop ? (
<EditExpenseModal
expense={expense}
expenseData={expenseData}
handleEditExpense={handleEditExpense}
setShowEditExpenseModal={setShowEditExpenseModal}
showEditExpenseModal={showEditExpenseModal}
/>
) : (
<EditExpense
expense={expense}
expenseData={expenseData}
handleEditExpense={handleEditExpense}
setShowEditExpenseModal={setShowEditExpenseModal}
/>
))}
{showDeleteExpenseModal && (
<DeleteExpenseModal
handleDeleteExpense={handleDeleteExpense}
setShowDeleteExpenseModal={setShowDeleteExpenseModal}
showDeleteExpenseModal={showDeleteExpenseModal}
/>
)}
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";

import { Categories } from "../../utils";
import { Categories } from "components/Expenses/utils";

const ExpensesSummary = () => (
<div className="flex w-full flex-wrap bg-miru-gray-100 px-4 py-10 lg:py-6 lg:px-20">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { DeleteIcon, EditIcon, DownloadSimpleIcon } from "miruIcons";
import { useNavigate } from "react-router-dom";
import { Tooltip, Modal, Button } from "StyledComponents";

import { DownloadAll } from "components/Expenses/utils";

const MoreOptions = ({
expense,
isDesktop,
Expand All @@ -18,7 +20,13 @@ const MoreOptions = ({
onClick={e => e.stopPropagation()}
>
<Tooltip content="Download">
<Button disabled style="ternary">
<Button
style="ternary"
onClick={e => {
e.stopPropagation();
DownloadAll(expense.receipts);
}}
>
<DownloadSimpleIcon size={16} weight="bold" />
</Button>
</Tooltip>
Expand All @@ -39,6 +47,7 @@ const MoreOptions = ({
style="ternary"
onClick={e => {
e.stopPropagation();
navigate(`/expenses/${expense.id}`);
}}
>
<DeleteIcon size={16} weight="bold" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,28 @@
import React, { Fragment, useState } from "react";

import { currencyFormat } from "helpers";
import { DotsThreeVerticalIcon, ExpenseIconSVG } from "miruIcons";
import { DotsThreeVerticalIcon, ExpenseIconSVG, InvoicesIcon } from "miruIcons";
import { useNavigate } from "react-router-dom";

import { Categories } from "components/Expenses/utils";
import { useUserContext } from "context/UserContext";

import MoreOptions from "./MoreOptions";

import { Categories } from "../../../utils";

const TableRow = ({ expense, currency }) => {
const navigate = useNavigate();
const { isDesktop } = useUserContext();
const { id, expenseType, amount, categoryName, date, vendorName } = expense;

const {
id,
expenseType,
amount,
categoryName,
date,
vendorName,
description,
receipts,
} = expense;

const [showMoreOptions, setShowMoreOptions] = useState<boolean>(false);

Expand Down Expand Up @@ -47,19 +56,19 @@ const TableRow = ({ expense, currency }) => {
</div>
</div>
</td>
<td className="hidden w-2/12 truncate py-4 pr-4 text-left text-base font-medium text-miru-dark-purple-1000 lg:table-cell">
<td className="hidden w-2/12 py-4 pr-4 text-left text-base font-medium text-miru-dark-purple-1000 lg:table-cell">
{date}
</td>
<td className="w-2/5 truncate py-4 pr-4 text-left lg:table-cell lg:w-2/12">
<td className="w-2/5 py-4 pr-4 text-left lg:table-cell lg:w-2/12">
<div className="flex w-full">
{!isDesktop && getCategoryIcon()}
<div className="flex flex-col items-start justify-start truncate">
<div className="flex flex-col items-start justify-start">
<span className="text-sm font-semibold text-miru-dark-purple-1000 lg:text-base">
{vendorName}
</span>
<span className="text-xs font-medium text-miru-dark-purple-400 lg:text-sm">
clientName
</span>
<p className="truncateOverflowText text-xs font-medium text-miru-dark-purple-400 lg:text-sm">
{description}
</p>
</div>
</div>
</td>
Expand All @@ -71,16 +80,23 @@ const TableRow = ({ expense, currency }) => {
</dl>
</div>
</td>
<td className="relative w-1/5 whitespace-nowrap py-4 pl-4 text-right text-sm lg:table-cell lg:w-2/12 lg:pr-2 lg:text-xl lg:font-bold">
{currencyFormat(currency, amount)}
{isDesktop && (
<MoreOptions
expense={expense}
isDesktop={isDesktop}
setShowMoreOptions={setShowMoreOptions}
showMoreOptions={showMoreOptions}
/>
)}
<td className="relative w-1/5 whitespace-nowrap py-4 pl-4 text-sm lg:w-2/12 lg:pr-2 lg:text-xl lg:font-bold">
<div className="flex items-center">
{receipts?.length > 0 && isDesktop && (
<InvoicesIcon size={24} weight="bold" />
)}
<span className="flex w-full justify-end">
{currencyFormat(currency, amount)}
</span>
{isDesktop && (
<MoreOptions
expense={expense}
isDesktop={isDesktop}
setShowMoreOptions={setShowMoreOptions}
showMoreOptions={showMoreOptions}
/>
)}
</div>
</td>
<td className="w-1/6 text-center lg:hidden">
<DotsThreeVerticalIcon
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ import React from "react";

import EmptyStates from "common/EmptyStates";

import ExpensesSummary from "./ExpensesSummary";
import Table from "./Table";

const Container = ({ expenseData }) => (
<div className="mt-6">
<ExpensesSummary />
{/* TODO: Uncomment and integrate when API is ready
<ExpensesSummary />
*/}
{expenseData?.expenses?.length > 0 ? (
<Table expenses={expenseData?.expenses} />
) : (
Expand Down