Skip to content

Commit

Permalink
Merge pull request #59 from TU-GitLio/feat/#58
Browse files Browse the repository at this point in the history
feat: Add portfolio view page
  • Loading branch information
POL6463 authored May 27, 2024
2 parents f865d13 + 506426b commit 138dc27
Show file tree
Hide file tree
Showing 15 changed files with 288 additions and 26 deletions.
33 changes: 33 additions & 0 deletions gitlio/actions/viewPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
'use client';
import axios from 'axios';
import IntroSidebarStore from '@/store/introSidebarStore';
import { useSidebarIconsStore } from '@/store/sidebarIconsStore';
import experienceSectionStore from '@/store/experienceSectionStore';
import { useProjectsStore } from '@/store/projectStore';
import ContactSidebarStore from '@/store/contactSidebarStore';

const API_URL = 'https://gitlio.fly.dev/api/';

export async function getPortfolioDataByDomain(domainName: string) {
const response = await axios.get(API_URL + 'portfolios/domain/' + domainName);
return response.data; // 백엔드에서 포트폴리오 데이터를 반환한다고 가정
}

export const updateStoresWithPortfolioData = async (domainName: string) => {
const portfolioData = await getPortfolioDataByDomain(domainName);

console.log('Fetched portfolio data:', portfolioData);

if (!portfolioData) {
console.error('Failed to fetch portfolio data');

return;
}

// Assuming `portfolioData` includes sections that correspond to data needed for each store
IntroSidebarStore.setState({ profile: portfolioData.introData });
useSidebarIconsStore.setState({ dropAreas: portfolioData.skillData });
experienceSectionStore.setState({ sections: portfolioData.experienceData });
useProjectsStore.setState({ projects: portfolioData.projectData });
ContactSidebarStore.setState({ contactInfo: portfolioData.contactData });
};
2 changes: 1 addition & 1 deletion gitlio/app/editor/[portfolioDomain]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ export default function EditPage({
<ExperienceSection />
</div>
<div className="mb-4 cursor-pointer">
<ProjSection />
<ProjSection isViewMode={false} />
</div>
<div
onClick={() => setSelectedSection('contact')}
Expand Down
46 changes: 46 additions & 0 deletions gitlio/app/editor/_components/(skill)/DraggableIconView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from 'react';
import { useDraggable } from '@dnd-kit/core';
import { IconType } from 'react-icons';
import { FaTimes } from 'react-icons/fa';
import { useSidebarIconsStore } from '@/store/sidebarIconsStore';
import usePreviewStore from '@/store/previewStore';
import { icons } from '@/app/editor/_components/(skill)/icons';

interface DraggableIconProps {
id: string;
IconComponent?: IconType;
label: string;
areaId?: string;
}

const DraggableIcon: React.FC<DraggableIconProps> = ({
id,
IconComponent,
label,
areaId,
}) => {
const logoExists = icons.hasOwnProperty(label);
if (logoExists) {
IconComponent = icons[label as keyof typeof icons];
}

const areaClass = areaId ? `area-${areaId}` : 'default-area';

return (
<div
className={`p-2 text-md font-semibold flex justify-between items-center bg-gray-200 rounded-lg ${areaClass}`}
aria-label={`Draggable icon for ${label}`}
role="button"
tabIndex={0}
>
<div className="flex-grow-1 flex items-center justify-start">
{' '}
{/* 드래그 리스너를 이 부분에만 적용 */}
{IconComponent && <IconComponent />}
<span className="ml-2 mr-2">{label}</span>
</div>
</div>
);
};

export default DraggableIcon;
30 changes: 30 additions & 0 deletions gitlio/app/editor/_components/(skill)/DropAreaComponentView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import { useSidebarIconsStore } from '@/store/sidebarIconsStore';
import DropArea from './DropArea';
import useLayoutStore from '@/store/layoutDesignStore';
import DropAreaView from '@/app/editor/_components/(skill)/DropAreaView';

const DropAreaComponent: React.FC = () => {
const { dropAreas } = useSidebarIconsStore();
const { skill } = useLayoutStore();

return (
<>
{dropAreas.slice(1).map((area) => (
<div key={area.id} className="mb-4 last:mb-0">
<div className="bg-white rounded-lg overflow-hidden">
{/* 타이틀 표시 추가 */}
<div
className={`p-2 ${skill.option === 'option2' ? 'bg-red-400' : 'bg-blue-500'} text-white text-center font-bold`}
>
{area.title}
</div>
<DropAreaView id={area.id} />
</div>
</div>
))}
</>
);
};

export default DropAreaComponent;
35 changes: 35 additions & 0 deletions gitlio/app/editor/_components/(skill)/DropAreaView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
'use client';
import React from 'react';
import { useSidebarIconsStore } from '@/store/sidebarIconsStore';
import DraggableIcon from './DraggableIcon';
import DraggableIconView from '@/app/editor/_components/(skill)/DraggableIconView';

interface DropAreaProps {
id: string;
}

const DropArea: React.FC<DropAreaProps> = ({ id }) => {
const { dropAreas } = useSidebarIconsStore();
const area = dropAreas.find((area) => area.id === id) || { icons: [] };

return (
<div className="min-w-[200px] min-h-[60px] h-auto bg-neutral-content/30 rounded flex flex-wrap items-center justify-center p-2">
{area.icons.length > 0 ? (
area.icons.map((icon) => (
<div className="m-2" key="">
<DraggableIconView
key={icon.id}
id={icon.id}
IconComponent={icon.logo}
label={icon.label}
/>
</div>
))
) : (
<p className="text-gray-500">Drop icons here</p>
)}
</div>
);
};

export default DropArea;
1 change: 0 additions & 1 deletion gitlio/app/editor/_components/TopBlogBar.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use client';
import ContactSidebarStore from '@/store/contactSidebarStore';
import { FaGithub, FaTwitter, FaLinkedin } from 'react-icons/fa';

export default function TopBlogBar() {
const { contactInfo } = ContactSidebarStore();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export default function ContactSection() {
const { contact } = useLayoutStore();

return (
<div className="bg-white w-[800px] flex flex-col flex-1 justify-start rounded-xl pb-5">
<div className="bg-white w-[800px] flex flex-col justify-start rounded-xl pb-5">
<h1 className="text-3xl font-semibold ml-10 mr-5 pt-5">#Contact</h1>
<div className="flex flex-col items-center h-full w-full mt-5">
<div
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export default function ExperienceSection() {
const { option } = experience;

return (
<div className="bg-white w-[800px] min-h-[200px] rounded-xl flex flex-col flex-1 justify-start">
<div className="bg-white w-[800px] min-h-[200px] rounded-xl flex flex-col justify-start">
<br />
<h1 className="text-3xl font-semibold ml-10 mr-5">#Experience</h1>
{option === 'option1' ? (
Expand Down
39 changes: 23 additions & 16 deletions gitlio/app/editor/_components/mainSection/ProjSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import ProjBox from './projComponents/ProjBox';
import { Data } from '@/app/editor/(interface)/ProjectData';
import ProjEditModal from './projComponents/ProjEditModal';

export default function ProjSection() {
interface ProjSectionProps {
isViewMode: boolean;
}
export default function ProjSection({ isViewMode }: ProjSectionProps) {
const { projects, setProjects, updateProject } = useProjectsStore();
const [isEditProjModalOpen, setIsEditProjModalOpen] = React.useState(false);
const [selectedRadio, setSelectedRadio] = React.useState(0);
Expand Down Expand Up @@ -37,21 +40,25 @@ export default function ProjSection() {
<br />
<div className="flex items-center -mb-3">
<h1 className="text-3xl font-semibold ml-10 mr-5">#Project</h1>
<div className="btn" onClick={handleToggleModal}>
편집
</div>
<div className="ml-5">
{[0, 1].map((index) => (
<input
key={index}
type="radio"
name="radio-1"
className="radio mr-2 mt-2"
checked={selectedRadio === index}
onChange={() => setSelectedRadio(index)}
/>
))}
</div>
{!isViewMode && (
<div className="btn" onClick={handleToggleModal}>
편집
</div>
)}
{!isViewMode && (
<div className="ml-5">
{[0, 1].map((index) => (
<input
key={index}
type="radio"
name="radio-1"
className="radio mr-2 mt-2"
checked={selectedRadio === index}
onChange={() => setSelectedRadio(index)}
/>
))}
</div>
)}
</div>
<div className="flex flex-col items-center">
{selectedRadio === 0 ? (
Expand Down
5 changes: 3 additions & 2 deletions gitlio/app/editor/_components/mainSection/SkillSection.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
'use client';
import React from 'react';
import DropAreaComponent from '@/app/editor/_components/(skill)/DropAreaComponent';
import DropAreaComponentView from '@/app/editor/_components/(skill)/DropAreaComponentView';

const SkillSection: React.FC = () => {
return (
<div className="bg-white w-[800px] min-h-[200px] flex flex-col flex-1 justify-start rounded-xl">
<div className="bg-white w-[800px] min-h-[200px] flex flex-col justify-start rounded-xl">
<br />
<h1 className="text-3xl font-semibold ml-10 mr-5">#Tech Stack</h1>
<div className="px-10 py-10">
<DropAreaComponent />
<DropAreaComponentView />
</div>
</div>
);
Expand Down
46 changes: 46 additions & 0 deletions gitlio/app/portfolio/[domainName]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use client';
import React, { useEffect, useState } from 'react';
import IntroSection from '@/app/editor/_components/mainSection/IntroSection';
import SkillSection from '@/app/editor/_components/mainSection/SkillSection';
import ExperienceSection from '@/app/editor/_components/mainSection/ExperienceSection';
import ProjSection from '@/app/editor/_components/mainSection/ProjSection';
import ContactSection from '@/app/editor/_components/mainSection/ContactSection';
import { updateStoresWithPortfolioData } from '@/actions/viewPage';

export default function PortfolioPage({
params,
}: {
params: { domainName: string };
}) {
const [loading, setLoading] = useState(true);

useEffect(() => {
const fetchData = async () => {
console.log('Fetching portfolio data for domain:', params.domainName);
await updateStoresWithPortfolioData(params.domainName);
setLoading(false);
};

fetchData();
}, [params.domainName]);

if (loading) {
return (
<div className="flex flex-col space-y-4">
<div className="flex justify-center items-center min-h-screen">
<span className="loading loading-spinner loading-lg"></span>
</div>
</div>
);
}

return (
<div className="flex flex-col space-y-4">
<IntroSection />
<SkillSection />
<ExperienceSection />
<ProjSection isViewMode={true} />
<ContactSection />
</div>
);
}
65 changes: 65 additions & 0 deletions gitlio/app/portfolio/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// EditorLayout.tsx
'use client';

import { SignedIn, SignedOut, SignInButton, UserButton } from '@clerk/nextjs';
import { useRouter } from 'next/navigation';
import Image from 'next/image';
import { FaSignInAlt } from 'react-icons/fa';
import React, { useEffect, useState } from 'react';

const EditorLayout: React.FC<{ children: React.ReactNode }> = ({
children,
}) => {
const router = useRouter();
const handleLogoClick = () => {
router.push('/studio/dashboard');
};

const [isClient, setIsClient] = useState(false);

useEffect(() => {
setIsClient(true);
}, []);

return (
<div className="flex flex-col min-h-screen bg-base-200">
<div className="navbar bg-neutral-800 fixed top-0 left-0 right-0 z-10">
<div className="flex-1">
<a
className="btn btn-ghost text-xl text-white hover:bg-base-300/20"
onClick={handleLogoClick}
>
<Image
src={'/logo_white_lg.svg'}
alt={'whiteLogo'}
width={30}
height={30}
/>
GITLIO
</a>
</div>
<div className="flex-none gap-6 pr-4">
{isClient && (
<>
<SignedOut>
<SignInButton>
<FaSignInAlt className="text-white size-6" />
</SignInButton>
</SignedOut>
<SignedIn>
<UserButton />
</SignedIn>
</>
)}
</div>
</div>
<div className="flex-grow flex overflow-hidden">
<div className="flex flex-col flex-grow mt-24 overflow-auto justify-center items-center">
<div className="flex mb-16">{children}</div>
</div>
</div>
</div>
);
};

export default EditorLayout;
2 changes: 1 addition & 1 deletion gitlio/store/contactSidebarStore.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import create from 'zustand';
import { create } from 'zustand';

interface BlogUrl {
id: string;
Expand Down
4 changes: 2 additions & 2 deletions gitlio/store/layoutDesignStore.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import create from 'zustand';
import { create } from 'zustand';

//객체로 그룹화 해서 리팩토링 완료!
interface LayoutOptions {
Expand All @@ -15,7 +15,7 @@ interface LayoutProps {

const useLayoutStore = create<LayoutProps>((set) => ({
intro: {
option: 'option1',
option: 'option3',
setOption: (option: string) =>
set((state) => ({ intro: { ...state.intro, option } })),
},
Expand Down
2 changes: 1 addition & 1 deletion gitlio/store/previewStore.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// store/previewStore.ts
import create from 'zustand';
import { create } from 'zustand';

interface PreviewState {
preview: boolean;
Expand Down

0 comments on commit 138dc27

Please sign in to comment.