Skip to content

Commit

Permalink
Merge pull request #3 from NotoSgnikusnsi/feat/save-data
Browse files Browse the repository at this point in the history
feat: 保存ボタンを押したとき,データをIndexedDBに保存する
  • Loading branch information
NotoSgnikusnsi authored Sep 7, 2024
2 parents 91deedf + 6cedade commit fd5ed15
Show file tree
Hide file tree
Showing 3 changed files with 180 additions and 5 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,9 @@
- [x]ユーザーに位置情報取得の許可を求め、エラーハンドリングを実装

3. **IndexedDBへのデータ保存**:
- IndexedDBに保存するためのデータベースをセットアップ
- 画像データと位置情報を保存するスキーマを設計
- 保存が成功した際、ユーザーに通知を表示
- [x] IndexedDBに保存するためのデータベースをセットアップ
- [x] 画像データと位置情報を保存するスキーマを設計
- [x] 保存が成功した際、ユーザーに通知を表示

4. **保存データの取得と表示**:
- IndexedDBから保存したデータを読み込み、簡単なUIで確認できるようにする
- [x] IndexedDBから保存したデータを読み込み、簡単なUIで確認できるようにする
93 changes: 92 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState } from "react";
import { useEffect, useState } from "react";
import "./App.css";
import {
ChakraProvider,
Expand All @@ -12,6 +12,8 @@ import {
Spinner,
} from "@chakra-ui/react";
import { ExternalLinkIcon } from "@chakra-ui/icons";
import { openDB, addRecord, fetchAllRecords } from "./indexedbdClient.ts";
import type { Place } from "./indexedbdClient.ts";

function App() {
const [selectedImage, setSelectedImage] = useState<string | null>(null);
Expand All @@ -20,6 +22,53 @@ function App() {
lon: number;
} | null>(null);
const [isLoadingLocation, setIsLoadingLocation] = useState(false);
const [db, setDb] = useState<IDBDatabase | null>(null);
const [records, setRecords] = useState<Place[]>([]);
const [isDBLoading, setIsDBLoading] = useState(false);

const loadAllRecords = () => {
setIsDBLoading(true);
if (db) {
fetchAllRecords(db)
.then((records) => {
setRecords(records);
setIsDBLoading(false);
})
.catch(() => {
console.error("Error fetching records");
setIsDBLoading(false);
});
} else {
alert("データベースにアクセスできません");
setIsDBLoading(false);
}
};

const handleAddRecord = () => {
if (db && selectedImage && currentLocation) {
const newRecord: Place = {
id: Date.now().toString(),
img: selectedImage as string,
location: {
lat: currentLocation?.lat as number,
lon: currentLocation?.lon as number,
},
};

addRecord(db, newRecord)
.then(() => {
console.log("Record added successfully");
setSelectedImage(null);
setCurrentLocation(null);
loadAllRecords();
})
.catch(() => {
console.error("Error adding record");
});
} else {
alert("データが不足しています");
}
};

const fetchCurrentLocation = () => {
setIsLoadingLocation(true);
Expand Down Expand Up @@ -61,6 +110,23 @@ function App() {
reader.readAsDataURL(selectFile);
};

useEffect(() => {
openDB()
.then((db) => {
setDb(db);
console.log("データベースにアクセスしました!!!");
})
.catch((error) => {
console.error("データベースにアクセスできません!!!", error);
});
}, []);

useEffect(() => {
if (db) {
loadAllRecords();
}
}, [db]);

return (
<>
<ChakraProvider>
Expand Down Expand Up @@ -107,6 +173,31 @@ function App() {
style={{ maxWidth: "300px", height: "auto" }}
/>
)}
<Button colorScheme="blue" onClick={handleAddRecord} mb={"4px"}>
データを保存する
</Button>
{isDBLoading ? (
<Spinner />
) : (
records.map((record) => (
<Box key={record.id} mb={"4px"}>
<img
src={record.img}
alt="record"
style={{ maxWidth: "300px", height: "auto" }}
/>
<Link
isExternal
href={`https://www.openstreetmap.org/#map=18/${record.location.lat}/${record.location.lon}`}
>
<Text mb={"4px"}>
緯度: {record.location.lat}, 経度: {record.location.lon}
<ExternalLinkIcon mx="2px" />
</Text>
</Link>
</Box>
))
)}
</Box>
</Container>
</ChakraProvider>
Expand Down
84 changes: 84 additions & 0 deletions src/indexedbdClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
type Place = {
id: string;
img: string;
location: {
lat: number;
lon: number;
};
};

const dbName = "test_ashiato";
let db: IDBDatabase | null = null;

const openDB = (): Promise<IDBDatabase> => {
return new Promise((resolve, reject) => {
const request = indexedDB.open(dbName, 1);

request.onupgradeneeded = (event) => {
const db = (event.target as IDBOpenDBRequest).result;

const objStore = db.createObjectStore("places", { keyPath: "id" });
objStore.createIndex("img", "img", { unique: true });
objStore.createIndex("location", "location", { unique: false });
};

request.onerror = (event) => {
console.error("データベースにアクセスできません!!!");
reject(event);
};

request.onsuccess = function (event) {
db = (event.target as IDBOpenDBRequest).result;
console.log("データベースにアクセスしました!!!");
resolve(db);
};
});
};

const addRecord = (db: IDBDatabase, record: Place): Promise<void> => {
return new Promise((resolve, reject) => {
const transaction = db.transaction("places", "readwrite");
const objStore = transaction.objectStore("places");

const request = objStore.add(record);

request.onerror = function () {
console.error("Error adding record");
reject();
};

request.onsuccess = function () {
console.log("Record added successfully");
resolve();
};
});
};

const fetchAllRecords = (db: IDBDatabase): Promise<Place[]> => {
const records: Place[] = [];
return new Promise((resolve, reject) => {
const transaction = db.transaction("places", "readonly");
const objStore = transaction.objectStore("places");

const request = objStore.openCursor();

request.onerror = function () {
console.error("Error getting records");
reject();
};

request.onsuccess = function (e) {
const cursor = (e.target as IDBRequest<IDBCursorWithValue>).result;
if (cursor) {
records.push(cursor.value);
cursor.continue();
} else {
console.log("No more records");
resolve(records);
}
};
});
};

export { openDB, addRecord, fetchAllRecords };
export type { Place };

0 comments on commit fd5ed15

Please sign in to comment.