@@ -90,13 +120,15 @@
import { defineComponent } from 'vue'
import { useForm } from '@/hooks/useForm.hook'
import { useGitHubLogin } from '@/hooks/useGitHubLogin.hook'
+import { useFavoriteRepos } from '@/modules/repo/hooks/useFavoriteRepos.hook'
export default defineComponent({
name: 'WelcomeWord',
setup() {
- const { isLogged } = useGitHubLogin()
+ const { isLogged, username } = useGitHubLogin()
+ const { savedFavoriteRepos } = useFavoriteRepos()
- return { ...useForm(), isLogged }
+ return { ...useForm(), isLogged, username, savedFavoriteRepos }
}
})
@@ -107,6 +139,11 @@ export default defineComponent({
margin: auto;
display: flex;
flex-direction: column;
+
+ h3,
+ h4 {
+ text-align: center;
+ }
}
footer {
diff --git a/src/data/DataType.enum.ts b/src/data/DataType.enum.ts
index dd99f09..773f872 100644
--- a/src/data/DataType.enum.ts
+++ b/src/data/DataType.enum.ts
@@ -1,3 +1,4 @@
export enum DataType {
- GithubAccessToken = 'GithubAccessToken'
+ GithubAccessToken = 'GithubAccessToken',
+ FavoriteRepo = 'FavoriteRepo'
}
diff --git a/src/data/data.ts b/src/data/data.ts
index 1bb49ef..80b2036 100644
--- a/src/data/data.ts
+++ b/src/data/data.ts
@@ -10,10 +10,11 @@ interface GetAllParams {
prefix?: string
includeDocs?: boolean
includeAttachments?: boolean
+ keys?: string[]
}
class Data {
- private locale = new PouchDb('local-db', {
+ private locale = new PouchDb('lite-note', {
adapter: 'indexeddb'
})
@@ -28,6 +29,24 @@ class Data {
}
}
+ public async update
(model: Model): Promise {
+ try {
+ if (model._id) {
+ const oldModel = await this.get(model._id)
+ if (oldModel) {
+ const result = await this.locale.put({ ...oldModel, ...model })
+ return result.ok
+ }
+ }
+ const result = await this.locale.put(model)
+ return result.ok
+ } catch (error) {
+ console.warn(error)
+
+ return false
+ }
+ }
+
public async remove(id: string): Promise {
try {
const doc = await this.get(id)
@@ -57,8 +76,19 @@ class Data {
public async getAll>({
prefix,
includeDocs = true,
- includeAttachments = false
+ includeAttachments = false,
+ keys = []
}: GetAllParams): Promise {
+ if (keys.length) {
+ const response = await this.locale.allDocs({
+ include_docs: includeDocs,
+ attachments: includeAttachments,
+ keys: keys.map((key) => this.generateId(prefix, key))
+ })
+
+ return response.rows.map((row) => row.doc).filter((doc) => !!doc) as T[]
+ }
+
const response = await this.locale.allDocs({
include_docs: includeDocs,
attachments: includeAttachments,
@@ -69,7 +99,11 @@ class Data {
return response.rows.map((row) => row.doc) as T[]
}
- public generateId(type: DataType, id?: string) {
+ public generateId(type?: DataType | string, id?: string) {
+ if (!type) {
+ return id || nanoid()
+ }
+
return `${type}-${id || nanoid()}`
}
}
diff --git a/src/hooks/useRepos.hook.ts b/src/hooks/useRepos.hook.ts
index 4aa28ac..6720d4d 100644
--- a/src/hooks/useRepos.hook.ts
+++ b/src/hooks/useRepos.hook.ts
@@ -1,10 +1,11 @@
import { Octokit } from '@octokit/rest'
+import { RepoBase } from '@/modules/interfaces/RepoBase'
import { useAsyncState } from '@vueuse/core'
import { useGitHubLogin } from '@/hooks/useGitHubLogin.hook'
export const useRepos = () => {
const { username, accessToken } = useGitHubLogin()
- const repos = useAsyncState(async () => {
+ const repos = useAsyncState(async () => {
if (!accessToken.value || !username.value) {
return []
}
@@ -18,7 +19,11 @@ export const useRepos = () => {
per_page: 100
})
- return repoList.data.items.map((item) => item.name)
+ return repoList.data.items.map((item) => ({
+ id: `${item.id}`,
+ name: item.name,
+ isPrivate: item.private
+ }))
}, [])
return {
diff --git a/src/modules/interfaces/RepoBase.ts b/src/modules/interfaces/RepoBase.ts
new file mode 100644
index 0000000..bd350ab
--- /dev/null
+++ b/src/modules/interfaces/RepoBase.ts
@@ -0,0 +1,5 @@
+export interface RepoBase {
+ id: string
+ name: string
+ isPrivate: boolean
+}
diff --git a/src/modules/models/FavoriteRepo.ts b/src/modules/models/FavoriteRepo.ts
new file mode 100644
index 0000000..b81b588
--- /dev/null
+++ b/src/modules/models/FavoriteRepo.ts
@@ -0,0 +1,8 @@
+import { DataType } from '@/data/DataType.enum'
+import { Model } from '@/data/models/Model'
+
+export interface FavoriteRepo extends Model {
+ isFavorite: boolean
+ isPrivate: boolean
+ name: string
+}
diff --git a/src/modules/repo/hooks/useFavoriteRepos.hook.ts b/src/modules/repo/hooks/useFavoriteRepos.hook.ts
new file mode 100644
index 0000000..b831887
--- /dev/null
+++ b/src/modules/repo/hooks/useFavoriteRepos.hook.ts
@@ -0,0 +1,47 @@
+import { computed, onMounted, ref } from 'vue'
+
+import { DataType } from '@/data/DataType.enum'
+import { FavoriteRepo } from '@/modules/models/FavoriteRepo'
+import { RepoBase } from '@/modules/interfaces/RepoBase'
+import { data } from '@/data/data'
+import { useRepos } from '@/hooks/useRepos.hook'
+
+export const useFavoriteRepos = () => {
+ const { repos } = useRepos()
+ const savedRepos = ref([])
+
+ const getFavorites = async () => {
+ savedRepos.value = await data.getAll({
+ prefix: DataType.FavoriteRepo,
+ keys: repos.value.map((repo) => repo.id)
+ })
+ }
+
+ const savedFavoriteRepos = computed(() =>
+ savedRepos.value.filter((repo) => repo.isFavorite)
+ )
+
+ onMounted(() => {
+ getFavorites()
+ })
+
+ const toggleFavorite = async (repo: RepoBase, isFavorite: boolean) => {
+ const favorite: FavoriteRepo = {
+ _id: data.generateId(DataType.FavoriteRepo, repo.id),
+ $type: DataType.FavoriteRepo,
+ isFavorite,
+ name: repo.name,
+ isPrivate: repo.isPrivate
+ }
+
+ await data.update(favorite)
+ await getFavorites()
+ }
+
+ return {
+ savedRepos,
+ savedFavoriteRepos,
+ addFavorite: (repo: RepoBase) => toggleFavorite(repo, true),
+ removeFavorite: (repo: RepoBase) => toggleFavorite(repo, false)
+ }
+}
diff --git a/src/modules/repo/hooks/userRepoList.hook.ts b/src/modules/repo/hooks/userRepoList.hook.ts
new file mode 100644
index 0000000..9f839b8
--- /dev/null
+++ b/src/modules/repo/hooks/userRepoList.hook.ts
@@ -0,0 +1,42 @@
+import { RepoBase } from '@/modules/interfaces/RepoBase'
+import { computed } from 'vue'
+import { useFavoriteRepos } from '@/modules/repo/hooks/useFavoriteRepos.hook'
+import { useRepos } from '@/hooks/useRepos.hook'
+
+export const useRepoList = () => {
+ const { savedFavoriteRepos, addFavorite, removeFavorite } = useFavoriteRepos()
+ const { repos } = useRepos()
+
+ const favoriteRepos = computed(() => {
+ return repos.value.filter((repo) =>
+ savedFavoriteRepos.value.find(
+ (fav) => fav._id?.includes(repo.id) ?? false
+ )
+ )
+ })
+
+ const otherRepos = computed(() => {
+ return repos.value.filter(
+ (repo) => !favoriteRepos.value.find((favorite) => favorite.id === repo.id)
+ )
+ })
+
+ const favoriteCheckboxes = computed(() =>
+ favoriteRepos.value.map((favorite) => favorite.id)
+ )
+
+ const toggleCheckbox = async (repo: RepoBase) => {
+ if (favoriteCheckboxes.value.includes(repo.id)) {
+ await removeFavorite(repo)
+ } else {
+ await addFavorite(repo)
+ }
+ }
+
+ return {
+ favoriteRepos,
+ otherRepos,
+ favoriteCheckboxes,
+ toggleCheckbox
+ }
+}
diff --git a/src/styles/app.scss b/src/styles/app.scss
index b750282..7055766 100644
--- a/src/styles/app.scss
+++ b/src/styles/app.scss
@@ -1,8 +1,8 @@
@charset "utf-8";
@import url('https://fonts.googleapis.com/css2?family=Courier+Prime&display=swap');
-$primary: #2C3A47;
-$link: #58B19F;
+$primary: #2c3a47;
+$link: #58b19f;
@import '~bulma/bulma.sass';
diff --git a/src/views/RepoList.vue b/src/views/RepoList.vue
index 918fdeb..a5e6db0 100644
--- a/src/views/RepoList.vue
+++ b/src/views/RepoList.vue
@@ -1,32 +1,88 @@
-
Repositories
+
+
Repositories
loading...
-
+