Skip to content

Commit

Permalink
feat: add location data when posting news
Browse files Browse the repository at this point in the history
  • Loading branch information
narol1024 committed May 24, 2024
1 parent f3e864f commit 99d8d06
Show file tree
Hide file tree
Showing 16 changed files with 134 additions and 50 deletions.
4 changes: 2 additions & 2 deletions app/api/add-news/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import { createHash } from "crypto";

export async function POST(request: Request) {
try {
const { secretKey, content } = await request.json();
const { secretKey, content, longitude, latitude } = await request.json();
if (!secretKey || !content) {
throw new Error("secretKey and content required");
}
const md5 = createHash("md5");
const pwd = md5.update(secretKey).digest("hex");
const { rows } = await sql`SELECT * FROM Users WHERE pwd=${pwd}`;
if (rows.length === 1) {
await sql`INSERT INTO news (content, "ownerId") VALUES (${content}, ${rows[0].id});`;
await sql`INSERT INTO news ("ownerId", content, longitude, latitude) VALUES (${rows[0].id}, ${content}, ${longitude}, ${latitude});`;
return NextResponse.json({
message: "Succeeded to publish",
result: {
Expand Down
4 changes: 3 additions & 1 deletion app/api/create-news-table/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ export async function GET(request: Request) {
"ownerId" integer,
"content" varchar(1024),
"picture" varchar(255),
"createdTime" TIMESTAMP DEFAULT CURRENT_TIMESTAMP
"createdTime" TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
"latitude" float,
"longitude" float
);
`;
return NextResponse.json({ result }, { status: 200 });
Expand Down
3 changes: 2 additions & 1 deletion app/api/create-users-table/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ export async function GET() {
"id" serial NOT NULL,
"username" varchar(255),
"avatarId" int,
"pwd" varchar(255)
"pwd" varchar(255),
"createdTime" TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
`;
return NextResponse.json({ result }, { status: 200 });
Expand Down
71 changes: 52 additions & 19 deletions app/home/Cobe/index.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
"use client";

import createGlobe from "cobe";
import { useEffect, useRef } from "react";
import { useEffect, useRef, useState } from "react";
import { useSpring } from "react-spring";
import { useStores } from "@/hooks/useStores";
import { observer } from "mobx-react-lite";

export function Cobe() {
export const Cobe = observer(() => {
const { news, location } = useStores();
const focusRef = useRef([-1, -1]);
const canvasRef = useRef<HTMLCanvasElement>(null);
const pointerInteracting = useRef<{ x: number; y: number } | null>(null);
const pointerInteractionMovement = useRef({
x: 0,
y: 0,
});
const [{ rx, ry }, api] = useSpring(() => ({
const [{ rx, ry }, springApi] = useSpring(() => ({
rx: 0,
ry: 0,
config: {
Expand All @@ -21,10 +25,20 @@ export function Cobe() {
precision: 0.001,
},
}));
const locationToAngles = (long: number, lat: number) => {
return [
Math.PI - ((long * Math.PI) / 180 - Math.PI / 2),
(lat * Math.PI) / 180,
];
};
useEffect(() => {
let phi = 0;
let theta = 0;
let width = 0;
let currentPhi = 0;
let currentTheta = 0;
const doublePi = Math.PI * 2;

if (canvasRef.current) {
width = canvasRef.current.offsetWidth;
const onResize = () =>
Expand All @@ -45,19 +59,32 @@ export function Cobe() {
markerColor: [251 / 255, 100 / 255, 21 / 255],
glowColor: [1.2, 1.2, 1.2],
markers: [
// longitude latitude
{ location: [37.7595, -122.4367], size: 0.03 },
{ location: [40.7128, -74.006], size: 0.1 },
],
onRender: (state) => {
// This prevents rotation while dragging
if (!pointerInteracting.current) {
// Called on every animation frame.
// `state` will be an empty object, return updated params.
phi += 0.005;
const isAutoRotation =
focusRef.current[0] === -1 && focusRef.current[1] === -1;
if (isAutoRotation) {
if (!pointerInteracting.current) {
phi += 0.005;
}
state.phi = phi + rx.get();
state.theta = theta + ry.get();
} else {
state.phi = currentPhi;
state.theta = currentTheta;
const [focusPhi, focusTheta] = focusRef.current;
const distPositive = (focusPhi - currentPhi + doublePi) % doublePi;
const distNegative = (currentPhi - focusPhi + doublePi) % doublePi;
// Control the speed
if (distPositive < distNegative) {
currentPhi += distPositive * 0.08;
} else {
currentPhi -= distNegative * 0.08;
}
currentTheta = currentTheta * 0.92 + focusTheta * 0.08;
}
state.phi = phi + rx.get();
state.theta = theta + ry.get();
state.width = width * 2;
state.height = width * 2;
},
Expand All @@ -68,6 +95,16 @@ export function Cobe() {
};
}
}, []);
useEffect(() => {
if (news.showPublishModal) {
focusRef.current = locationToAngles(
location.longitude,
location.latitude
);
} else {
focusRef.current = [-1, -1];
}
}, [news.showPublishModal]);
return (
<div
style={{
Expand Down Expand Up @@ -99,7 +136,7 @@ export function Cobe() {
y: e.clientY - pointerInteracting.current.y,
};
pointerInteractionMovement.current = delta;
api.start({
springApi.start({
rx: delta.x / 200,
ry: delta.y / 200,
});
Expand All @@ -112,18 +149,14 @@ export function Cobe() {
y: e.touches[0].clientY - pointerInteracting.current.y,
};
pointerInteractionMovement.current = delta;
api.start({
springApi.start({
rx: delta.x / 100,
ry: delta.y / 100,
});
}
}}
style={{
width: "100%",
height: "100%",
cursor: "grab",
}}
className="w-full h-full cursor-grab"
/>
</div>
);
}
});
19 changes: 19 additions & 0 deletions app/home/Location/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"use client";

import React, { useEffect } from "react";
import { observer } from "mobx-react-lite";
import { useStores } from "@/hooks/useStores";
import { useGeolocation } from "@uidotdev/usehooks";

export const Location = observer(() => {
const locationResult = useGeolocation();
const { location } = useStores();

useEffect(() => {
if (locationResult.longitude && locationResult.latitude) {
location.updateLongitude(locationResult.longitude);
location.updateAltitude(locationResult.latitude);
}
}, [locationResult]);
return <></>;
});
1 change: 1 addition & 0 deletions app/home/News/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const News = observer(() => {
useEffect(() => {
(async () => {
const res = await fetch("/api/news", {
cache: "no-store",
method: "GET",
});
const { result } = await res.json();
Expand Down
25 changes: 14 additions & 11 deletions app/home/Publish/index.tsx → app/home/Post/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
ModalBody,
ModalFooter,
Button,
Input,
Textarea,
} from "@nextui-org/react";
import { CameraIcon } from "../icons/CameraIcon";
Expand All @@ -17,13 +16,12 @@ import { useModal } from "@ebay/nice-modal-react";
import Message from "../Message";
import { useStores } from "@/hooks/useStores";

export const Publish = observer(() => {
export const Post = observer(() => {
const [isPublishLoading, setIsPublishLoading] = useState(false);
const [content, setContent] = useState("温馨提示,再不睡头发就要掉光光喽。");
const { user, news, location } = useStores();
const messageModal = useModal(Message);
const { user, news } = useStores();
const userInfo = user.userInfo;

return (
<>
<Modal
Expand Down Expand Up @@ -52,13 +50,16 @@ export const Publish = observer(() => {
defaultValue={content}
onValueChange={setContent}
/>
<Button
variant="ghost"
color="default"
startContent={<CameraIcon />}
>
上传图片
</Button>
<div className="flex gap-2 justify-between items-center">
<Button
size="md"
variant="ghost"
color="default"
startContent={<CameraIcon width={16} height={16} />}
>
图片
</Button>
</div>
</ModalBody>
<ModalFooter>
<Button color="danger" variant="light" onPress={onClose}>
Expand All @@ -75,6 +76,8 @@ export const Publish = observer(() => {
body: JSON.stringify({
content: content,
secretKey: userInfo.secretKey,
longitude: location.longitude,
latitude: location.latitude,
}),
});
const { result } = await res.json();
Expand Down
2 changes: 1 addition & 1 deletion app/home/icons/CameraIcon.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from "react";

export const CameraIcon = ({
fill = "currentColor",
fill = "#ffffff",
height = 24,
width = 24,
...props
Expand Down
6 changes: 0 additions & 6 deletions app/home/icons/ExploreIcon.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ export const ExploreIcon = ({
cy="5.5"
r="2.5"
fill="#ffffff"
className="color000 svgShape"
></circle>
<path
fill="none"
Expand All @@ -30,14 +29,12 @@ export const ExploreIcon = ({
strokeMiterlimit="10"
strokeWidth="2"
d="M12.5 6h14"
className="colorStroke000 svgStroke"
></path>
<circle
cx="5"
cy="14.5"
r="2.5"
fill="#ffffff"
className="color000 svgShape"
></circle>
<path
fill="none"
Expand All @@ -47,14 +44,12 @@ export const ExploreIcon = ({
strokeMiterlimit="10"
strokeWidth="2"
d="M12.5 15h14"
className="colorStroke000 svgStroke"
></path>
<circle
cx="5"
cy="23.5"
r="2.5"
fill="#ffffff"
className="color000 svgShape"
></circle>
<path
fill="none"
Expand All @@ -64,7 +59,6 @@ export const ExploreIcon = ({
strokeMiterlimit="10"
strokeWidth="2"
d="M12.5 24h14"
className="colorStroke000 svgStroke"
></path>
</svg>
</g>
Expand Down
16 changes: 16 additions & 0 deletions app/home/icons/GeoIcon.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@


import React from "react";

export const GeoIcon = ({
fill = "#ffffff",
height = 24,
width = 24,
...props
}) => {
return (
<svg width={width} height={height} viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill={fill} {...props}>
<path d="M8 16s6-5.686 6-10A6 6 0 0 0 2 6c0 4.314 6 10 6 10zm0-7a3 3 0 1 1 0-6 3 3 0 0 1 0 6z"/>
</svg>
);
};
6 changes: 4 additions & 2 deletions app/home/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import React from "react";
import { Button, Image, Link } from "@nextui-org/react";
import { Cobe } from "./Cobe";
import { News } from "./News";
import { Publish } from "./Publish";
import { Post } from "./Post";
import { Location } from "./Location";
import { Register } from "./Register";
import { Login } from "./Login";
import avatar from "@/assets/logo.png";
Expand All @@ -21,8 +22,9 @@ const HomePage = observer(() => {
<Cobe />
<Register />
<Login />
<Publish />
<Post />
<News />
<Location />
{!isLogined && (
<div className="flex justify-center gap-10">
<Button
Expand Down
15 changes: 15 additions & 0 deletions app/stores/LocationStore.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { makeAutoObservable } from "mobx";

export class LocationStore {
longitude: number = -1;
latitude: number = -1;
constructor() {
makeAutoObservable(this);
}
updateLongitude = (longitude: number) => {
this.longitude = longitude;
};
updateAltitude = (latitude: number) => {
this.latitude = latitude;
};
}
3 changes: 0 additions & 3 deletions app/stores/NewsStore.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { NewsData } from "@/types";
import { makeAutoObservable } from "mobx";
import { enableStaticRendering } from "mobx-react-lite";

enableStaticRendering(typeof window === "undefined");

export class NewsStore {
newsList: NewsData[] = [];
Expand Down
3 changes: 0 additions & 3 deletions app/stores/UserStore.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import { UserInfo } from "@/types";
import { makeAutoObservable } from "mobx";
import { enableStaticRendering } from "mobx-react-lite";
import { makePersistable } from "mobx-persist-store";

enableStaticRendering(typeof window === "undefined");

export class UserStore {
userInfo: Partial<UserInfo> = {};
showRegisterModal = false;
Expand Down
Loading

0 comments on commit 99d8d06

Please sign in to comment.