From 34ccc98a942098faefb5f4211b215ff9ccc7ad0e Mon Sep 17 00:00:00 2001
From: Alexander Neonxp Kiryukhin <i@neonxp.ru>
Date: Mon, 9 Dec 2024 01:07:15 +0300
Subject: Начальный
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 frontend/app.jsx | 207 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 207 insertions(+)
 create mode 100644 frontend/app.jsx

(limited to 'frontend/app.jsx')

diff --git a/frontend/app.jsx b/frontend/app.jsx
new file mode 100644
index 0000000..60bdcf4
--- /dev/null
+++ b/frontend/app.jsx
@@ -0,0 +1,207 @@
+import React, { useState, useEffect } from "react";
+import GlMap, { Source, Marker, Layer } from "react-map-gl/maplibre";
+import {
+    Flex,
+    Layout,
+    Col,
+    Row,
+    Modal,
+    Form,
+    Input,
+    Button,
+    Image,
+    Card,
+} from "antd";
+
+const { Header, Content } = Layout;
+
+const layout = {
+    labelCol: { span: 8 },
+    wrapperCol: { span: 16 },
+};
+
+const geostyle = {
+    id: "data",
+    type: "line",
+    paint: {
+        "line-color": "red",
+        "line-width": 3,
+    },
+};
+
+const App = () => {
+    const [state, setState] = useState({});
+    const [selected, setSelected] = useState(null);
+    const [guess, setGuess] = useState(null);
+    const [loading, setLoading] = useState(true);
+    const [form] = Form.useForm();
+
+    useEffect(() => {
+        fetch("/api/state")
+            .then((x) => x.json())
+            .then(setState)
+            .then(() => setLoading(false));
+    }, []);
+
+    useEffect(() => {
+        if (guess != null) {
+            setState(guess.state);
+        }
+    }, [guess]);
+
+    const onFinish = (values) => {
+        fetch("/api/state", {
+            method: "POST",
+            body: JSON.stringify(values),
+            headers: { "content-type": "application/json" },
+        })
+            .then((x) => x.json())
+            .then(setState);
+    };
+
+    const onReset = () => {
+        form.resetFields();
+    };
+
+    const onNext = () => {
+        setSelected(null);
+        setGuess(null);
+        setLoading(true);
+        fetch("/api/next", {
+            method: "POST",
+            headers: { "content-type": "application/json" },
+        })
+            .then((x) => x.json())
+            .then(setState)
+            .then(() => setLoading(false));
+    };
+
+    const onMapClick = (e) => {
+        if (state.current_guid) {
+            setSelected(e.lngLat);
+        }
+    };
+
+    const onGuess = () => {
+        setLoading(true);
+        fetch("/api/guess", {
+            method: "POST",
+            headers: { "content-type": "application/json" },
+            body: JSON.stringify(selected),
+        })
+            .then((x) => x.json())
+            .then(setGuess)
+            .then(() => setLoading(false));
+    };
+
+    return (
+        <>
+            <Layout>
+                <Content>
+                    <Row style={{ height: "100vh" }}>
+                        <Col sm={16}>
+                            <GlMap
+                                initialViewState={{
+                                    longitude: 49.106414,
+                                    latitude: 55.796127,
+                                    zoom: 11,
+                                }}
+                                onClick={onMapClick}
+                                style={{ width: "100%", height: "100%" }}
+                                mapStyle="https://tiles.openfreemap.org/styles/liberty"
+                            >
+                                {selected ? (
+                                    <Marker
+                                        latitude={selected.lat}
+                                        longitude={selected.lng}
+                                    />
+                                ) : null}
+                                {guess ? (
+                                    <Source
+                                        type="geojson"
+                                        data={JSON.parse(guess.geojson)}
+                                    >
+                                        <Layer {...geostyle} />
+                                    </Source>
+                                ) : null}
+                            </GlMap>
+                        </Col>
+                        <Col sm={8}>
+                            {state.username ? (
+                                <Card>
+                                    <h1>{state.username}</h1>
+                                    <h2>{state.points} очков</h2>
+                                </Card>
+                            ) : null}
+                            <Card>
+                                {!loading && !state.current_guid ? (
+                                    <Button
+                                        type="primary"
+                                        onClick={onNext}
+                                        block
+                                        size="large"
+                                    >
+                                        Новое задание
+                                    </Button>
+                                ) : null}
+                                {!loading && state.current_guid ? (
+                                    <Image src={state.image} />
+                                ) : null}
+                                {!loading && guess ? (
+                                    <>
+                                        <h2>{guess.name}</h2>
+                                        <Image src={guess.image} />
+                                        <h3>Расстояние: {guess.distance / 1000}км.</h3>
+                                    </>
+                                ) : null}
+                                {state.current_guid && !selected ? (
+                                    <p>
+                                        Нажмите на карте на точку, где по вашему
+                                        мнение находится то, что на фотографии
+                                    </p>
+                                ) : null}
+                                {state.current_guid && selected ? (
+                                    <Button
+                                        type="primary"
+                                        onClick={onGuess}
+                                        block
+                                        size="large"
+                                    >
+                                        Проверить
+                                    </Button>
+                                ) : null}
+                            </Card>
+                            <p>Сделал <a href="https://neonxp.ru">Александр Кирюхин</a> в 2024 году</p>
+                        </Col>
+                    </Row>
+                </Content>
+            </Layout>
+            <Modal
+                title="Представьтесь"
+                open={!loading && !state.username}
+                onOk={form.submit}
+                onCancel={onReset}
+            >
+                <p>Для начала игры необходимо представиться</p>
+                <Form
+                    {...layout}
+                    form={form}
+                    name="control-hooks"
+                    onFinish={onFinish}
+                    style={{ maxWidth: 600 }}
+                >
+                    <Form.Item
+                        name="username"
+                        label="Имя"
+
+                        rules={[{ required: true }]}
+                    >
+                        <Input />
+                    </Form.Item>
+                </Form>
+            </Modal>
+        </>
+    );
+};
+
+export default App;
-- 
cgit v1.2.3

