diff --git a/api/db/member.go b/api/db/member.go
index 78e6a046b775cbdf6205115b995aa90bc7c68a87..cbce9549248680f01ede90afe284412064ce3afc 100644
--- a/api/db/member.go
+++ b/api/db/member.go
@@ -128,6 +128,7 @@ func (d DB) Login(login, password string) (member Member, err error) {
 	cleanedLogin := cleanLogin(login)
 	err = d.db.Where("email = ?", cleanedLogin).
 		First(&member).Error
+
 	if err != nil {
 		err = d.db.Where("login = ?", cleanedLogin).
 			First(&member).Error
diff --git a/api/db/transaction.go b/api/db/transaction.go
index bf597571d6a5ece10fd4f93bb6ed0324bce289ca..d4d56b23565fb393b9a6735d9b642af403d704ae 100644
--- a/api/db/transaction.go
+++ b/api/db/transaction.go
@@ -43,9 +43,36 @@ type Purchase struct {
 	Amount        int     `json:"amount"`
 }
 
-func (d *DB) ListTransactions() (transactions []Transaction, err error) {
-	err = d.transactionQuery().
-		Order("date desc").
+func (d *DB) ListTransactions(query map[string][]string) (transactions []Transaction, err error) {
+	const dateLayout = "2006-01-02"
+	tx := d.transactionQuery()
+	for k, v := range query {
+		switch k {
+		case "start-date":
+			var date time.Time
+			date, err = time.Parse(dateLayout, v[0])
+			if err != nil {
+				return
+			}
+			tx = tx.Where("date >= ?", date)
+		case "end-date":
+			var date time.Time
+			date, err = time.Parse(dateLayout, v[0])
+			if err != nil {
+				return
+			}
+			tx = tx.Where("date <= ?", date)
+		case "member":
+			tx = tx.Where("member_num in ?", v)
+		case "proxy":
+			tx = tx.Where("proxy_num in ?", v)
+		case "type":
+			tx = tx.Where("type in ?", v)
+		default:
+			log.Printf("Unexpected transaction query: %s %v", k, v)
+		}
+	}
+	err = tx.Order("date desc").
 		Find(&transactions).Error
 	return
 }
diff --git a/api/transaction.go b/api/transaction.go
index bd5d2c461aa80e10c13e10406e823f67e5069206..c70c31ce475392c2257f2cfc3a601f9d23d1edc4 100644
--- a/api/transaction.go
+++ b/api/transaction.go
@@ -12,7 +12,14 @@ import (
 )
 
 func (a *api) ListTransactions(w http.ResponseWriter, req *http.Request) {
-	transactions, err := a.db.ListTransactions()
+	err := req.ParseForm()
+	if err != nil {
+		log.Printf("Can't parse the query: %v", err)
+		w.WriteHeader(http.StatusInternalServerError)
+		return
+	}
+
+	transactions, err := a.db.ListTransactions(req.Form)
 	if err != nil {
 		log.Printf("Can't list transactions: %v", err)
 		w.WriteHeader(http.StatusInternalServerError)
diff --git a/src/Dashboard.js b/src/Dashboard.js
index ff4bf76a1bc0b68578275f39128955d363531f13..ac17ef6ac66dab91f000ab7c94be544f4a99f957 100644
--- a/src/Dashboard.js
+++ b/src/Dashboard.js
@@ -4,7 +4,7 @@ import { LinkContainer } from "react-router-bootstrap";
 import AuthContext from "./AuthContext";
 import Fetcher from "./Fetcher";
 import OrderList from "./order/OrderList";
-import TransactionList from "./TransactionList";
+import MyTransactions from "./transaction/MyTransactions";
 import { printMoney } from "./util";
 
 class Dashboard extends React.Component {
@@ -41,7 +41,7 @@ class Dashboard extends React.Component {
           </Col>
         </Row>
         <OrderList />
-        <TransactionList />
+        <MyTransactions />
       </Fetcher>
     );
   }
diff --git a/src/Head.js b/src/Head.js
index 8c40792d6d773f691902ed92753061a887da52a6..c05aba48445a142d5d4eddad9f9e00d01e1b8ed1 100644
--- a/src/Head.js
+++ b/src/Head.js
@@ -25,6 +25,9 @@ function Head(props) {
         <LinkContainer to="/members/add">
           <NavDropdown.Item>Nueva socia</NavDropdown.Item>
         </LinkContainer>
+        <LinkContainer to="/transaction">
+          <NavDropdown.Item>Transacciones</NavDropdown.Item>
+        </LinkContainer>
       </NavDropdown>
     );
   }
diff --git a/src/Panel.js b/src/Panel.js
index b1aaaea5e4cd5f639c929e9cfd62cfce7d481193..8dc728d11612d19ffc058d5ff6c10ca0f8834ace 100644
--- a/src/Panel.js
+++ b/src/Panel.js
@@ -9,7 +9,8 @@ import Dashboard from "./Dashboard";
 import OwnPassword from "./OwnPassword";
 import Purchase from "./purchase/Purchase";
 import Topup from "./Topup";
-import ShowTransaction from "./ShowTransaction";
+import ShowTransaction from "./transaction/ShowTransaction";
+import TransactionList from "./transaction/TransactionList";
 import ShowOrder from "./order/ShowOrder";
 import CreateOrder from "./order/CreateOrder";
 import EditOrder from "./order/EditOrder";
@@ -51,6 +52,9 @@ function LogedPanel(props) {
             <Route path="/transaction/:id">
               <ShowTransaction />
             </Route>
+            <Route path="/transaction">
+              <TransactionList />
+            </Route>
             <Route path="/password">
               <OwnPassword />
             </Route>
diff --git a/src/TransactionList.js b/src/TransactionList.js
deleted file mode 100644
index 45aa3cbbf46184ca6f9b9dbbb797f28841d4ce27..0000000000000000000000000000000000000000
--- a/src/TransactionList.js
+++ /dev/null
@@ -1,108 +0,0 @@
-import React, { useState } from "react";
-import { Table, OverlayTrigger, Popover } from "react-bootstrap";
-import { LinkContainer } from "react-router-bootstrap";
-import { FaShoppingBasket, FaMoneyBillAlt } from "react-icons/fa";
-import { GiPayMoney, GiReceiveMoney } from "react-icons/gi";
-import { HiClipboardCopy, HiClipboardList } from "react-icons/hi";
-import Fetcher from "./Fetcher";
-import { printMoney, printDate } from "./util";
-
-function icon(transaction) {
-  switch (transaction.type) {
-    case "purchase":
-      return <FaShoppingBasket />;
-    case "topup":
-      if (transaction.total < 0) {
-        return <GiReceiveMoney />;
-      }
-      return <GiPayMoney />;
-    case "order":
-      return <HiClipboardList />;
-    case "refund":
-      return <HiClipboardCopy />;
-    default:
-      return <FaMoneyBillAlt />;
-  }
-}
-
-function transactionOverlay(transaction) {
-  let title;
-  let content;
-  switch (transaction.type) {
-    case "purchase":
-      title = "compra";
-      content = transaction.purchase.map((p) => p.product.name).join(",") + ".";
-      break;
-    case "topup":
-      if (transaction.total < 0) {
-        title = "devolución";
-      } else {
-        title = "recarga";
-      }
-      content = transaction.topup.comment;
-      break;
-    case "order":
-      title = "pedido de " + transaction.order.name;
-      content = transaction.order_purchase.map((p) => {
-        return (
-          <div key={"O" + transaction.ID + "-" + p.order_product.ID}>
-            {p.order_product.product.name + ": " + p.amount}
-            <br />
-          </div>
-        );
-      });
-      break;
-    case "refund":
-      title = "devolución de " + transaction.refund.name;
-      break;
-    default:
-      title = "transacción";
-  }
-  return (
-    <Popover>
-      <Popover.Title>{title}</Popover.Title>
-      {content && <Popover.Content>{content}</Popover.Content>}
-    </Popover>
-  );
-}
-
-function TransactionList() {
-  const [transactions, setTransactions] = useState([]);
-
-  // TODO: useEffect to disable fetcher...
-
-  const entries = transactions.map((transaction) => {
-    const colorClass = transaction.total < 0 ? "table-danger" : "table-success";
-    return (
-      <OverlayTrigger
-        overlay={transactionOverlay(transaction)}
-        key={transaction.ID}
-      >
-        <LinkContainer to={"/transaction/" + transaction.ID}>
-          <tr className={colorClass}>
-            <td>{icon(transaction)}</td>
-            <td>{printDate(transaction.date)}</td>
-            <td>{printMoney(transaction.total) + " €"}</td>
-          </tr>
-        </LinkContainer>
-      </OverlayTrigger>
-    );
-  });
-
-  return (
-    <Fetcher url="/api/transaction/mine" onFetch={setTransactions}>
-      <Table className="text-center">
-        <thead>
-          <tr>
-            <th></th>
-            <th>Fecha</th>
-            <th>Cantidad</th>
-          </tr>
-        </thead>
-        <tbody>{entries}</tbody>
-      </Table>
-    </Fetcher>
-  );
-}
-
-export default TransactionList;
diff --git a/src/member/MemberPicker.js b/src/member/MemberPicker.js
index 6b714ae9e783432ee8005ecc3933088e16834a21..c45bff2112c2fe8455456834994dda11d1b60305 100644
--- a/src/member/MemberPicker.js
+++ b/src/member/MemberPicker.js
@@ -23,12 +23,14 @@ function MemberPicker(props) {
     }
   };
 
+  const text = props.text ? props.text : "Socia";
+
   return (
     <Fetcher url="/api/member" onFetch={setMembers}>
       <Form.Row>
         <Col sm={4}>
           <br />
-          <h4 className="text-right">Socia:</h4>
+          <h4 className="text-right">{text}:</h4>
         </Col>
         <Form.Group as={Col} sm={2}>
           <Form.Label>Num</Form.Label>
diff --git a/src/order/OrderEditor.js b/src/order/OrderEditor.js
index 3484dde9942c5aeae085b5151e86c43348868827..f4c5e08ae9d931b43b993a36f621be85bac8e844 100644
--- a/src/order/OrderEditor.js
+++ b/src/order/OrderEditor.js
@@ -2,16 +2,7 @@ import React, { useState } from "react";
 import { Form, Row, Col } from "react-bootstrap";
 import ProductPicker from "../ProductPicker";
 import Fetcher from "../Fetcher";
-
-function date2string(date) {
-  return date.toISOString().split("T")[0];
-}
-
-function daysAfterNow(days) {
-  let date = new Date();
-  date.setDate(date.getDate() + days);
-  return date;
-}
+import { daysAfterNow, date2string } from "../util";
 
 function order2picks(order) {
   return order.products.map((p) => {
diff --git a/src/transaction/MyTransactions.js b/src/transaction/MyTransactions.js
new file mode 100644
index 0000000000000000000000000000000000000000..1b0494496388e00b12e1d55fdcaf3134d809c41b
--- /dev/null
+++ b/src/transaction/MyTransactions.js
@@ -0,0 +1,37 @@
+import React, { useState } from "react";
+import { Table } from "react-bootstrap";
+import icon from "./icon";
+import TransactionTr from "./TransactionTr";
+import Fetcher from "../Fetcher";
+import { printMoney, printDate } from "../util";
+
+function MyTransactions() {
+  const [transactions, setTransactions] = useState([]);
+
+  const entries = transactions.map((transaction) => {
+    return (
+      <TransactionTr transaction={transaction}>
+        <td>{icon(transaction)}</td>
+        <td>{printDate(transaction.date)}</td>
+        <td>{printMoney(transaction.total) + " €"}</td>
+      </TransactionTr>
+    );
+  });
+
+  return (
+    <Fetcher url="/api/transaction/mine" onFetch={setTransactions}>
+      <Table className="text-center">
+        <thead>
+          <tr>
+            <th></th>
+            <th>Fecha</th>
+            <th>Cantidad</th>
+          </tr>
+        </thead>
+        <tbody>{entries}</tbody>
+      </Table>
+    </Fetcher>
+  );
+}
+
+export default MyTransactions;
diff --git a/src/ShowTransaction.js b/src/transaction/ShowTransaction.js
similarity index 81%
rename from src/ShowTransaction.js
rename to src/transaction/ShowTransaction.js
index 22dcebe241bbe632422268d0c060e580b0bd923a..569df30d12e7bbc74565f2b6027e04376468c74b 100644
--- a/src/ShowTransaction.js
+++ b/src/transaction/ShowTransaction.js
@@ -1,9 +1,9 @@
 import React, { useState } from "react";
 import { useParams, Redirect } from "react-router-dom";
 import { Row, Col } from "react-bootstrap";
-import Fetcher from "./Fetcher";
-import ShowPurchase from "./purchase/ShowPurchase";
-import { printMoney, printDate } from "./util";
+import Fetcher from "../Fetcher";
+import ShowPurchase from "../purchase/ShowPurchase";
+import { printMoney, printDate } from "../util";
 
 function ShowTransaction() {
   const { id } = useParams();
@@ -31,10 +31,11 @@ function ShowTransaction() {
       <Row>
         <Col>
           <h3>Total: {printMoney(transaction.total)}€</h3>
+          {transaction.member && <p>{transaction.member.name}</p>}
         </Col>
         <Col>
           <p className="text-right">
-            {printDate(transaction.date)}
+            {printDate(transaction.date)} {"T-" + transaction.ID}
             {transaction.proxy && (
               <span>
                 <br />
diff --git a/src/transaction/TransactionList.js b/src/transaction/TransactionList.js
new file mode 100644
index 0000000000000000000000000000000000000000..83c458501d8288270384c2a88bb23dc8faf20b19
--- /dev/null
+++ b/src/transaction/TransactionList.js
@@ -0,0 +1,112 @@
+import React, { useState } from "react";
+import { Table, Form, Row, Col } from "react-bootstrap";
+import icon from "./icon";
+import TransactionTr from "./TransactionTr";
+import MemberPicker from "../member/MemberPicker";
+import Fetcher from "../Fetcher";
+import { printMoney, printDate, daysAfterNow, date2string } from "../util";
+
+const engType = {
+  compra: "purchase",
+  recarga: "topup",
+  pedido: "order",
+  devolucion: "refund",
+};
+
+function TransactionList() {
+  const [transactions, setTransactions] = useState([]);
+  const [startDate, setStartDate] = useState(date2string(daysAfterNow(-30)));
+  const [endDate, setEndDate] = useState(date2string(new Date()));
+  const [member, setMember] = useState(null);
+  const [proxy, setProxy] = useState(null);
+  const [types, setTypes] = useState([]);
+
+  let query = "start-date=" + startDate + "&end-date=" + endDate;
+  if (member) {
+    query += "&member=" + member.num;
+  }
+  if (proxy) {
+    query += "&proxy=" + proxy.num;
+  }
+  query += types.map((t) => "&type=" + engType[t]);
+
+  const onTypeChange = (e) => {
+    const newTypes = Array.from(e.target.selectedOptions, (o) => o.value);
+    setTypes(newTypes);
+  };
+
+  const entries = transactions.map((transaction) => {
+    return (
+      <TransactionTr transaction={transaction}>
+        <td>{icon(transaction)}</td>
+        <td>{"T-" + transaction.ID}</td>
+        <td>{printDate(transaction.date)}</td>
+        <td>{transaction.member.name}</td>
+        <td>{transaction.proxy ? transaction.proxy.name : ""}</td>
+        <td>{printMoney(transaction.total) + " €"}</td>
+      </TransactionTr>
+    );
+  });
+
+  return (
+    <div>
+      <Form>
+        <Row>
+          <Form.Group as={Col}>
+            <Form.Label>Desde:</Form.Label>
+            <Form.Control
+              type="date"
+              value={startDate}
+              onChange={(e) => setStartDate(e.target.value)}
+              max={endDate}
+            />
+          </Form.Group>
+          <Form.Group as={Col}>
+            <Form.Label>Hasta:</Form.Label>
+            <Form.Control
+              type="date"
+              value={endDate}
+              onChange={(e) => setEndDate(e.target.value)}
+              min={startDate}
+              max={Date.now()}
+            />
+          </Form.Group>
+          <Form.Group as={Col}>
+            <Form.Label>Typo:</Form.Label>
+            <Form.Control
+              as="select"
+              value={types}
+              onChange={onTypeChange}
+              multiple
+            >
+              <option>compra</option>
+              <option>recarga</option>
+              <option>pedido</option>
+              <option>devolucion</option>
+            </Form.Control>
+          </Form.Group>
+        </Row>
+        <MemberPicker member={member} onChange={setMember} />
+        <MemberPicker member={proxy} onChange={setProxy} text="Por" />
+      </Form>
+      <br />
+      <Fetcher url={"/api/transaction?" + query} onFetch={setTransactions}>
+        <Table className="text-center">
+          <thead>
+            <tr>
+              <th></th>
+              <th>ID</th>
+              <th>Fecha</th>
+              <th>Socia</th>
+              <th>Por</th>
+              <th>Cantidad</th>
+            </tr>
+          </thead>
+          <tbody>{entries}</tbody>
+        </Table>
+      </Fetcher>
+    </div>
+  );
+}
+
+export default TransactionList;
diff --git a/src/transaction/TransactionTr.js b/src/transaction/TransactionTr.js
new file mode 100644
index 0000000000000000000000000000000000000000..8cffa391240eed26ff06ab9bb302c680df9657d6
--- /dev/null
+++ b/src/transaction/TransactionTr.js
@@ -0,0 +1,61 @@
+import React from "react";
+import { OverlayTrigger, Popover } from "react-bootstrap";
+import { LinkContainer } from "react-router-bootstrap";
+
+function transactionOverlay(transaction) {
+  let title;
+  let content;
+  switch (transaction.type) {
+    case "purchase":
+      title = "compra";
+      content = transaction.purchase.map((p) => p.product.name).join(",") + ".";
+      break;
+    case "topup":
+      if (transaction.total < 0) {
+        title = "devolución";
+      } else {
+        title = "recarga";
+      }
+      content = transaction.topup.comment;
+      break;
+    case "order":
+      title = "pedido de " + transaction.order.name;
+      content = transaction.order_purchase.map((p) => {
+        return (
+          <div key={"O" + transaction.ID + "-" + p.order_product.ID}>
+            {p.order_product.product.name + ": " + p.amount}
+            <br />
+          </div>
+        );
+      });
+      break;
+    case "refund":
+      title = "devolución de " + transaction.refund.name;
+      break;
+    default:
+      title = "transacción";
+  }
+  return (
+    <Popover>
+      <Popover.Title>{title}</Popover.Title>
+      {content && <Popover.Content>{content}</Popover.Content>}
+    </Popover>
+  );
+}
+
+function TransactionTr(props) {
+  const colorClass =
+    props.transaction.total < 0 ? "table-danger" : "table-success";
+  return (
+    <OverlayTrigger
+      overlay={transactionOverlay(props.transaction)}
+      key={props.transaction.ID}
+    >
+      <LinkContainer to={"/transaction/" + props.transaction.ID}>
+        <tr className={colorClass}>{props.children}</tr>
+      </LinkContainer>
+    </OverlayTrigger>
+  );
+}
+
+export default TransactionTr;
diff --git a/src/transaction/icon.js b/src/transaction/icon.js
new file mode 100644
index 0000000000000000000000000000000000000000..580c31dd2e29f57e59fffd8db6f4bedb1a5754f7
--- /dev/null
+++ b/src/transaction/icon.js
@@ -0,0 +1,24 @@
+import React from "react";
+import { FaShoppingBasket, FaMoneyBillAlt } from "react-icons/fa";
+import { GiPayMoney, GiReceiveMoney } from "react-icons/gi";
+import { HiClipboardCopy, HiClipboardList } from "react-icons/hi";
+
+function icon(transaction) {
+  switch (transaction.type) {
+    case "purchase":
+      return <FaShoppingBasket />;
+    case "topup":
+      if (transaction.total < 0) {
+        return <GiReceiveMoney />;
+      }
+      return <GiPayMoney />;
+    case "order":
+      return <HiClipboardList />;
+    case "refund":
+      return <HiClipboardCopy />;
+    default:
+      return <FaMoneyBillAlt />;
+  }
+}
+
+export default icon;
diff --git a/src/util.js b/src/util.js
index 02685239a293c87348e9c9fe858e4659cdcdd04c..98e361beef610bf507a249898de49ca898b60d46 100644
--- a/src/util.js
+++ b/src/util.js
@@ -25,4 +25,14 @@ function url(path) {
   return api + path;
 }
 
-export { printMoney, printDate, printRole, url };
+function daysAfterNow(days) {
+  let date = new Date();
+  date.setDate(date.getDate() + days);
+  return date;
+}
+
+function date2string(date) {
+  return date.toISOString().split("T")[0];
+}
+
+export { printMoney, printDate, printRole, url, daysAfterNow, date2string };