Skip to content

Commit

Permalink
feat: add emoji-picker-react package to frontend dependencies
Browse files Browse the repository at this point in the history
  • Loading branch information
MiguelMedeiros committed Aug 27, 2024
1 parent c63fdbc commit 839d972
Show file tree
Hide file tree
Showing 11 changed files with 203 additions and 33 deletions.
2 changes: 2 additions & 0 deletions 0_backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
"main": "index.js",
"scripts": {
"start:start": "ts-node src/index.ts",
"start:prod": "ts-node src/index.ts",
"build": "tsc",
"start:dev": "nodemon --exec ts-node src/index.ts",
"test": "echo \"Error: no test specified\" && exit 1"
},
Expand Down
34 changes: 34 additions & 0 deletions 0_backend/src/services/_db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,39 @@ async function countInvoices(db: any) {
}
}

async function getAllInvoicesDeactivated(
db: any,
limit: number,
offset: number
) {
if (!db) return null;

try {
return await db.all(
`
SELECT
message,
amount,
lat_long,
deactivate_at,
updated_at
FROM invoices
WHERE
message IS NOT NULL
AND status = 'paid'
AND deactivate_at <= strftime('%s', 'now')
ORDER BY deactivate_at DESC
LIMIT ?
OFFSET ?
`,
[limit, offset]
);
} catch (error) {
console.error(error);
return null;
}
}

async function getAllInvoices(db: any, limit: number, offset: number) {
if (!db) return null;

Expand Down Expand Up @@ -235,5 +268,6 @@ export {
checkInvoiceExists,
getAllInvoices,
getInvoiceByInvoice,
getAllInvoicesDeactivated,
countInvoices,
};
31 changes: 27 additions & 4 deletions 0_backend/src/services/_express.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
countInvoices,
createInvoice,
getAllInvoices,
getAllInvoicesDeactivated,
getInvoiceByInvoice,
updateInvoiceStatus,
} from "./_db";
Expand Down Expand Up @@ -51,10 +52,10 @@ const initExpress = async ({ phoenix, db }: Props) => {
return;
}

// (timestamp) deactivate_at = current date + amount * 10 seconds
// (timestamp) deactivate_at = current date + amount * 60 seconds
const deactivate_at = new Date();
deactivate_at.setSeconds(
deactivate_at.getSeconds() + invoiceUpdated?.amount * 10
deactivate_at.getSeconds() + invoiceUpdated?.amount * 60
);
const timestamp = Math.floor(deactivate_at.getTime() / 1000);

Expand Down Expand Up @@ -170,13 +171,35 @@ const initExpress = async ({ phoenix, db }: Props) => {
}
});

app.get("/invoices/deactivated", async (req, res) => {
try {
const { page = 1, limit = 10 } = req.query;

const pageNumber = parseInt(page as string, 10);
const limitNumber = parseInt(limit as string, 10);

const offset = (pageNumber - 1) * limitNumber;

const invoices = await getAllInvoicesDeactivated(
db,
limitNumber,
offset
);

return res.json({ invoices });
} catch (error: any) {
console.log(error);
res.status(500).json({ error: error.message });
}
});

app.post("/new-invoice", async (req, res) => {
try {
const { message, amount, websocket_id, lat_long } = req.body;

// (timestamp) deactivate_at = current date + amount * 10 seconds
// (timestamp) deactivate_at = current date + amount * 60 seconds
const deactivate_at = new Date();
deactivate_at.setSeconds(deactivate_at.getSeconds() + amount * 10);
deactivate_at.setSeconds(deactivate_at.getSeconds() + amount * 60);
const timestamp = Math.floor(deactivate_at.getTime() / 1000);

if (!message || !amount || !websocket_id) {
Expand Down
28 changes: 24 additions & 4 deletions 1_frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions 1_frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
},
"dependencies": {
"axios": "^1.7.4",
"emoji-picker-react": "^4.11.1",
"express": "^4.19.2",
"leaflet": "^1.9.4",
"lucide-react": "^0.428.0",
Expand Down
4 changes: 4 additions & 0 deletions 1_frontend/public/map-pin-check-inside-deactivated.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions 1_frontend/src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@ const Header = ({
}) => {
return (
<div className="flex items-center px-8 py-2 w-full bg-indigo-700 shadow-2xl h-[56px]">
<a href="/" className="flex items-center">
<Link href="/" className="flex items-center">
<h1 className="text-3xl font-bold text-white">zapin.me</h1>
</a>
</Link>
<span className="text-pink-100 text-[10px] mt-3 ml-1">v{version}</span>
<div className="flex-1" />
<div className="flex items-center text-white space-x-6 gap-1">
Expand Down
38 changes: 38 additions & 0 deletions 1_frontend/src/components/MapComponent/_MapComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ interface TimeLeft {
seconds: number;
}

const deactivatedIcon = icon({
iconUrl: "./map-pin-check-inside-deactivated.svg",
iconSize: [30, 30],
iconAnchor: [12, 41],
popupAnchor: [1, -34],
});

const customIcon = icon({
iconUrl: "./map-pin-check-inside.svg",
iconSize: [40, 40],
Expand Down Expand Up @@ -124,6 +131,7 @@ const Map = ({
markers,
setMarkers,
fetchTotalPins,
marketListDeactivated,
}: {
markers: {
amount: number;
Expand All @@ -134,6 +142,7 @@ const Map = ({
}[];
fetchTotalPins: () => void;
setMarkers: any;
marketListDeactivated: any;
}) => {
const handleRemoveMarker = async (index: number) => {
setMarkers((prevMarkers: any[]) =>
Expand Down Expand Up @@ -163,6 +172,35 @@ const Map = ({
attribution=""
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
/>
{marketListDeactivated.map((marker: any, index: number) => {
const lat = parseFloat(marker.lat_long.split(",")[0]);
const long = parseFloat(marker.lat_long.split(",")[1]);

return (
<Marker key={index} position={[lat, long]} icon={deactivatedIcon}>
<Popup>
<div className="relative px-6 py-1 bg-gray-800 text-white rounded-lg shadow-md w-full min-w-[250px]">
<div className="flex items-center mb-0">
<Zap className="w-4 h-4 text-yellow-500 mr-1" />
<p className="text-sm text-yellow-500 font-semibold">
{marker.amount}
</p>
</div>

<h2 className="text-[18px] font-medium text-white mb-0">
{marker.message}
</h2>

<p className="text-xs text-gray-300 text-right">
Deactivated
</p>

<div className="absolute bottom-[-7px] left-1/2 transform -translate-x-1/2 w-0 h-0 border-t-8 border-t-gray-800 border-x-8 border-x-transparent"></div>
</div>
</Popup>
</Marker>
);
})}
{markers.map((marker, index) => {
const lat = parseFloat(marker.lat_long.split(",")[0]);
const long = parseFloat(marker.lat_long.split(",")[1]);
Expand Down
39 changes: 36 additions & 3 deletions 1_frontend/src/components/Stage0.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
/* eslint-disable react-hooks/exhaustive-deps */
import axios from "axios";
import { Eraser, Send } from "lucide-react";
import { Eraser, File, Send, Smile } from "lucide-react";
import { useState, useEffect } from "react";
import { z } from "zod";
import { CreatePinMap } from "./MapComponent";
import EmojiPicker from "emoji-picker-react";

const NEXT_PUBLIC_BACKEND_URL = process.env.NEXT_PUBLIC_BACKEND_URL;

Expand Down Expand Up @@ -50,6 +51,7 @@ const Stage0 = ({
const [isDeleting, setIsDeleting] = useState<boolean>(false);
const [loopNum, setLoopNum] = useState<number>(0);
const [typingSpeed, setTypingSpeed] = useState<number>(150);
const [showEmojiPicker, setShowEmojiPicker] = useState(false);

const placeholders = [
"What's your pin-worthy message?",
Expand Down Expand Up @@ -88,7 +90,7 @@ const Stage0 = ({
}, [placeholder, isDeleting, typingSpeed, loopNum]);

const calculateActiveTime = (sats: number) => {
const totalSeconds = sats * 10;
const totalSeconds = sats * 60;

const years = Math.floor(totalSeconds / (365 * 24 * 3600));
const months = Math.floor(
Expand Down Expand Up @@ -149,22 +151,53 @@ const Stage0 = ({
}
};

const onEmojiClick = (emojiObject: { emoji: string }) => {
setMessage(message + emojiObject.emoji);
setShowEmojiPicker(false);
};

return (
<div className="flex flex-col space-y-2 w-full max-w-[700px] rounded-lg">
<h2 className="text-2xl font-bold text-white mb-2">
Drop a pin and leave your mark!
</h2>

<div className="space-y-2">
<div className="">
<textarea
placeholder={placeholder}
value={message}
onChange={(e) => setMessage(e.target.value)}
className="w-full text-gray-900 px-4 py-3 rounded-md bg-gray-100 focus:outline-none focus:ring-2 focus:ring-purple-500 transition duration-200 h-32 resize-none"
/>

<button
type="button"
onClick={() => {
setShowEmojiPicker(!showEmojiPicker);
}}
className="absolute bg-pink-400 rounded-full p-2 text-white mt-[8.5vh] -ml-[45px] hover:text-white hover:bg-pink-500"
>
<Smile size={20} />
</button>

{/* <button
type="button"
onClick={() => {
setShowEmojiPicker(!showEmojiPicker);
}}
className="ml-2 relative bg-purple-400 rounded-full p-2 text-white mt-2 mb-2 hover:text-gray-600"
>
<File size={20} />
</button> */}

{errors.message && (
<p className="text-pink-500 text-sm">{errors.message}</p>
)}
{showEmojiPicker && (
<div className="absolute z-10 ml-[250px]">
<EmojiPicker onEmojiClick={onEmojiClick} />
</div>
)}
</div>

<div className="space-y-2">
Expand Down
21 changes: 11 additions & 10 deletions 1_frontend/src/pages/about.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,34 +41,35 @@ export default function Home() {
a message on a global map for all to see, while also supporting
open-source development.
</p>

<h2 className="text-2xl font-bold text-pink-200 mb-4 pt-10">
How It Works
</h2>
<p className="text-lg">
On <span className="font-bold">zapin.me</span>, each message you pin
is fueled by Satoshis. For every Satoshi you donate, your message
stays visible on the map for{" "}
<span className="font-bold text-yellow-300">
10 seconds per Satoshi
</span>
. This means that you have full control over how long your message
is fueled by Satoshis.
</p>
<div className="text-lg font-bold text-yellow-300 my-4">
1 minute = 1 Satoshi
</div>
<p className="text-lg">
This means that you have full control over how long your message
remains on the map. For example:
</p>
<ul className="list-disc list-inside text-lg ml-4">
<li>
<span className="font-bold text-yellow-300">1 Satoshi</span> keeps
your message visible for 10 seconds.
your message visible for 1 minute.
</li>
<li>
<span className="font-bold text-yellow-300">360 Satoshis</span>{" "}
keeps your message visible for 1 hour.
keeps your message visible for 6 hours.
</li>
<li>
<span className="font-bold text-yellow-300">3600 Satoshis</span>{" "}
keeps your message visible for 10 hours.
keeps your message visible for 60 hours.
</li>
</ul>

<p className="text-lg">
It&apos;s a fun and interactive way to engage with the community and
maybe even earn a few Satoshis along the way!
Expand Down
Loading

0 comments on commit 839d972

Please sign in to comment.