Build Nuxt 4 client cabinet with Apollo and GraphQL flows
This commit is contained in:
24
.gitignore
vendored
Normal file
24
.gitignore
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
# Nuxt dev/build outputs
|
||||
.output
|
||||
.data
|
||||
.nuxt
|
||||
.nitro
|
||||
.cache
|
||||
dist
|
||||
|
||||
# Node dependencies
|
||||
node_modules
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
|
||||
# Misc
|
||||
.DS_Store
|
||||
.fleet
|
||||
.idea
|
||||
|
||||
# Local env files
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
12
.storybook/main.ts
Normal file
12
.storybook/main.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
import type { StorybookConfig } from '@storybook/vue3-vite';
|
||||
|
||||
const config: StorybookConfig = {
|
||||
stories: ['../app/**/*.stories.@(ts|tsx)'],
|
||||
addons: ['@storybook/addon-essentials'],
|
||||
framework: {
|
||||
name: '@storybook/vue3-vite',
|
||||
options: {},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
15
.storybook/preview.ts
Normal file
15
.storybook/preview.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import type { Preview } from '@storybook/vue3-vite';
|
||||
import '../app/assets/css/main.css';
|
||||
|
||||
const preview: Preview = {
|
||||
parameters: {
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/i,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default preview;
|
||||
75
README.md
75
README.md
@@ -1,2 +1,75 @@
|
||||
# web-frontend
|
||||
# Nuxt Minimal Starter
|
||||
|
||||
Look at the [Nuxt documentation](https://nuxt.com/docs/getting-started/introduction) to learn more.
|
||||
|
||||
## Setup
|
||||
|
||||
Make sure to install dependencies:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm install
|
||||
|
||||
# pnpm
|
||||
pnpm install
|
||||
|
||||
# yarn
|
||||
yarn install
|
||||
|
||||
# bun
|
||||
bun install
|
||||
```
|
||||
|
||||
## Development Server
|
||||
|
||||
Start the development server on `http://localhost:3000`:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run dev
|
||||
|
||||
# pnpm
|
||||
pnpm dev
|
||||
|
||||
# yarn
|
||||
yarn dev
|
||||
|
||||
# bun
|
||||
bun run dev
|
||||
```
|
||||
|
||||
## Production
|
||||
|
||||
Build the application for production:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run build
|
||||
|
||||
# pnpm
|
||||
pnpm build
|
||||
|
||||
# yarn
|
||||
yarn build
|
||||
|
||||
# bun
|
||||
bun run build
|
||||
```
|
||||
|
||||
Locally preview production build:
|
||||
|
||||
```bash
|
||||
# npm
|
||||
npm run preview
|
||||
|
||||
# pnpm
|
||||
pnpm preview
|
||||
|
||||
# yarn
|
||||
yarn preview
|
||||
|
||||
# bun
|
||||
bun run preview
|
||||
```
|
||||
|
||||
Check out the [deployment documentation](https://nuxt.com/docs/getting-started/deployment) for more information.
|
||||
|
||||
8
app/app.vue
Normal file
8
app/app.vue
Normal file
@@ -0,0 +1,8 @@
|
||||
<template>
|
||||
<div>
|
||||
<AppHeader />
|
||||
<main class="container mx-auto p-4 md:p-6">
|
||||
<NuxtPage />
|
||||
</main>
|
||||
</div>
|
||||
</template>
|
||||
12
app/assets/css/main.css
Normal file
12
app/assets/css/main.css
Normal file
@@ -0,0 +1,12 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
:root {
|
||||
--brand-primary: #0f766e;
|
||||
--brand-secondary: #1d4ed8;
|
||||
}
|
||||
|
||||
body {
|
||||
@apply bg-base-200 text-base-content;
|
||||
}
|
||||
19
app/components/orders/OrderStatusBadge.stories.ts
Normal file
19
app/components/orders/OrderStatusBadge.stories.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
||||
import OrderStatusBadge from './OrderStatusBadge.vue';
|
||||
|
||||
const meta: Meta<typeof OrderStatusBadge> = {
|
||||
title: 'Orders/OrderStatusBadge',
|
||||
component: OrderStatusBadge,
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<typeof OrderStatusBadge>;
|
||||
|
||||
export const InProgress: Story = {
|
||||
args: { status: 'IN_PROGRESS' },
|
||||
};
|
||||
|
||||
export const Completed: Story = {
|
||||
args: { status: 'COMPLETED' },
|
||||
};
|
||||
16
app/components/orders/OrderStatusBadge.vue
Normal file
16
app/components/orders/OrderStatusBadge.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<script setup lang="ts">
|
||||
const props = defineProps<{
|
||||
status: string;
|
||||
}>();
|
||||
|
||||
const className = computed(() => {
|
||||
if (props.status === 'COMPLETED') return 'badge badge-success';
|
||||
if (props.status === 'CLIENT_REJECTED' || props.status === 'MANAGER_REJECTED') return 'badge badge-error';
|
||||
if (props.status === 'MANAGER_BLOCKED') return 'badge badge-warning';
|
||||
return 'badge badge-info';
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<span :class="className">{{ status }}</span>
|
||||
</template>
|
||||
13
app/components/ui/AppHeader.stories.ts
Normal file
13
app/components/ui/AppHeader.stories.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import type { Meta, StoryObj } from '@storybook/vue3-vite';
|
||||
import AppHeader from './AppHeader.vue';
|
||||
|
||||
const meta: Meta<typeof AppHeader> = {
|
||||
title: 'UI/AppHeader',
|
||||
component: AppHeader,
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<typeof AppHeader>;
|
||||
|
||||
export const Default: Story = {};
|
||||
15
app/components/ui/AppHeader.vue
Normal file
15
app/components/ui/AppHeader.vue
Normal file
@@ -0,0 +1,15 @@
|
||||
<template>
|
||||
<header class="navbar bg-base-100 border-b border-base-300 sticky top-0 z-10">
|
||||
<div class="navbar-start">
|
||||
<NuxtLink to="/" class="btn btn-ghost text-xl">Fregat</NuxtLink>
|
||||
</div>
|
||||
<div class="navbar-center hidden md:flex">
|
||||
<ul class="menu menu-horizontal px-1">
|
||||
<li><NuxtLink to="/products">Товары</NuxtLink></li>
|
||||
<li><NuxtLink to="/cart">Корзина</NuxtLink></li>
|
||||
<li><NuxtLink to="/orders">Заказы</NuxtLink></li>
|
||||
<li><NuxtLink to="/profile">Профиль</NuxtLink></li>
|
||||
</ul>
|
||||
</div>
|
||||
</header>
|
||||
</template>
|
||||
713
app/composables/graphql/generated.ts
Normal file
713
app/composables/graphql/generated.ts
Normal file
@@ -0,0 +1,713 @@
|
||||
import gql from 'graphql-tag';
|
||||
import * as VueApolloComposable from '@vue/apollo-composable';
|
||||
import type * as VueCompositionApi from '@vue/composition-api';
|
||||
export type Maybe<T> = T | null;
|
||||
export type InputMaybe<T> = Maybe<T>;
|
||||
export type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };
|
||||
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };
|
||||
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };
|
||||
export type MakeEmpty<T extends { [key: string]: unknown }, K extends keyof T> = { [_ in K]?: never };
|
||||
export type Incremental<T> = T | { [P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never };
|
||||
export type ReactiveFunction<TParam> = () => TParam;
|
||||
/** All built-in and custom scalars, mapped to their actual values */
|
||||
export type Scalars = {
|
||||
ID: { input: string; output: string; }
|
||||
String: { input: string; output: string; }
|
||||
Boolean: { input: boolean; output: boolean; }
|
||||
Int: { input: number; output: number; }
|
||||
Float: { input: number; output: number; }
|
||||
DateTime: { input: any; output: any; }
|
||||
JSON: { input: any; output: any; }
|
||||
};
|
||||
|
||||
export type AcceptInvitationInput = {
|
||||
fullName: Scalars['String']['input'];
|
||||
token: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
export type AddBonusTransactionInput = {
|
||||
amount: Scalars['Float']['input'];
|
||||
orderId?: InputMaybe<Scalars['ID']['input']>;
|
||||
reason: Scalars['String']['input'];
|
||||
userId: Scalars['ID']['input'];
|
||||
};
|
||||
|
||||
export type BlockOrderInput = {
|
||||
orderId: Scalars['ID']['input'];
|
||||
reason: Scalars['String']['input'];
|
||||
};
|
||||
|
||||
export type BonusTransaction = {
|
||||
__typename?: 'BonusTransaction';
|
||||
amount: Scalars['Float']['output'];
|
||||
createdAt: Scalars['DateTime']['output'];
|
||||
id: Scalars['ID']['output'];
|
||||
orderId?: Maybe<Scalars['ID']['output']>;
|
||||
reason: Scalars['String']['output'];
|
||||
userId: Scalars['ID']['output'];
|
||||
};
|
||||
|
||||
export type Company = {
|
||||
__typename?: 'Company';
|
||||
id: Scalars['ID']['output'];
|
||||
inn?: Maybe<Scalars['String']['output']>;
|
||||
name: Scalars['String']['output'];
|
||||
};
|
||||
|
||||
export type ConnectMessengerInput = {
|
||||
channelId: Scalars['String']['input'];
|
||||
type: MessengerType;
|
||||
};
|
||||
|
||||
export type CreateInvitationInput = {
|
||||
companyName: Scalars['String']['input'];
|
||||
email: Scalars['String']['input'];
|
||||
expiresInDays?: InputMaybe<Scalars['Int']['input']>;
|
||||
};
|
||||
|
||||
export type CreateReferralInput = {
|
||||
refereeUserId: Scalars['ID']['input'];
|
||||
};
|
||||
|
||||
export enum Decision {
|
||||
Approve = 'APPROVE',
|
||||
Reject = 'REJECT'
|
||||
}
|
||||
|
||||
export type Invitation = {
|
||||
__typename?: 'Invitation';
|
||||
acceptedAt?: Maybe<Scalars['DateTime']['output']>;
|
||||
acceptedById?: Maybe<Scalars['ID']['output']>;
|
||||
companyName: Scalars['String']['output'];
|
||||
createdAt: Scalars['DateTime']['output'];
|
||||
email: Scalars['String']['output'];
|
||||
expiresAt: Scalars['DateTime']['output'];
|
||||
id: Scalars['ID']['output'];
|
||||
managerId: Scalars['ID']['output'];
|
||||
token: Scalars['String']['output'];
|
||||
};
|
||||
|
||||
export type MessengerConnection = {
|
||||
__typename?: 'MessengerConnection';
|
||||
channelId: Scalars['String']['output'];
|
||||
id: Scalars['ID']['output'];
|
||||
isActive: Scalars['Boolean']['output'];
|
||||
type: MessengerType;
|
||||
userId: Scalars['ID']['output'];
|
||||
};
|
||||
|
||||
export enum MessengerType {
|
||||
Max = 'MAX',
|
||||
Telegram = 'TELEGRAM'
|
||||
}
|
||||
|
||||
export type Mutation = {
|
||||
__typename?: 'Mutation';
|
||||
acceptInvitation: User;
|
||||
addBonusTransaction: BonusTransaction;
|
||||
blockOrder: Order;
|
||||
clientReviewOrder: Order;
|
||||
completeOrder: Order;
|
||||
connectMessenger: MessengerConnection;
|
||||
createInvitation: Invitation;
|
||||
createReferral: ReferralLink;
|
||||
managerFinalizeOrder: Order;
|
||||
managerSetOrderOffer: Order;
|
||||
registerSelf: RegistrationRequest;
|
||||
requestRewardWithdrawal: RewardWithdrawalRequest;
|
||||
reviewRegistrationRequest: RegistrationRequest;
|
||||
reviewRewardWithdrawal: RewardWithdrawalRequest;
|
||||
startOrderWork: Order;
|
||||
submitCalculationOrder: Order;
|
||||
submitReadyOrder: Order;
|
||||
};
|
||||
|
||||
|
||||
export type MutationAcceptInvitationArgs = {
|
||||
input: AcceptInvitationInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationAddBonusTransactionArgs = {
|
||||
input: AddBonusTransactionInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationBlockOrderArgs = {
|
||||
input: BlockOrderInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationClientReviewOrderArgs = {
|
||||
decision: Decision;
|
||||
orderId: Scalars['ID']['input'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationCompleteOrderArgs = {
|
||||
orderId: Scalars['ID']['input'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationConnectMessengerArgs = {
|
||||
input: ConnectMessengerInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationCreateInvitationArgs = {
|
||||
input: CreateInvitationInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationCreateReferralArgs = {
|
||||
input: CreateReferralInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationManagerFinalizeOrderArgs = {
|
||||
decision: Decision;
|
||||
orderId: Scalars['ID']['input'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationManagerSetOrderOfferArgs = {
|
||||
input: SetOrderOfferInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationRegisterSelfArgs = {
|
||||
input: RegisterSelfInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationRequestRewardWithdrawalArgs = {
|
||||
input: RequestRewardWithdrawalInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationReviewRegistrationRequestArgs = {
|
||||
input: ReviewRegistrationRequestInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationReviewRewardWithdrawalArgs = {
|
||||
input: ReviewRewardWithdrawalInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationStartOrderWorkArgs = {
|
||||
orderId: Scalars['ID']['input'];
|
||||
};
|
||||
|
||||
|
||||
export type MutationSubmitCalculationOrderArgs = {
|
||||
input: SubmitCalculationOrderInput;
|
||||
};
|
||||
|
||||
|
||||
export type MutationSubmitReadyOrderArgs = {
|
||||
input: SubmitReadyOrderInput;
|
||||
};
|
||||
|
||||
export type Order = {
|
||||
__typename?: 'Order';
|
||||
blockReason?: Maybe<Scalars['String']['output']>;
|
||||
calculationPayload?: Maybe<Scalars['JSON']['output']>;
|
||||
clientApproved?: Maybe<Scalars['Boolean']['output']>;
|
||||
code: Scalars['String']['output'];
|
||||
createdAt: Scalars['DateTime']['output'];
|
||||
customerId: Scalars['ID']['output'];
|
||||
deliveryFee?: Maybe<Scalars['Float']['output']>;
|
||||
deliveryTerms?: Maybe<Scalars['String']['output']>;
|
||||
history: Array<OrderStatusEvent>;
|
||||
id: Scalars['ID']['output'];
|
||||
items: Array<OrderItem>;
|
||||
kind: OrderKind;
|
||||
managerApproved?: Maybe<Scalars['Boolean']['output']>;
|
||||
managerId?: Maybe<Scalars['ID']['output']>;
|
||||
status: OrderStatus;
|
||||
totalPrice?: Maybe<Scalars['Float']['output']>;
|
||||
updatedAt: Scalars['DateTime']['output'];
|
||||
};
|
||||
|
||||
export type OrderItem = {
|
||||
__typename?: 'OrderItem';
|
||||
id: Scalars['ID']['output'];
|
||||
productId?: Maybe<Scalars['ID']['output']>;
|
||||
productName: Scalars['String']['output'];
|
||||
quantity: Scalars['Float']['output'];
|
||||
};
|
||||
|
||||
export enum OrderKind {
|
||||
Calculation = 'CALCULATION',
|
||||
Ready = 'READY'
|
||||
}
|
||||
|
||||
export enum OrderStatus {
|
||||
ClientRejected = 'CLIENT_REJECTED',
|
||||
Completed = 'COMPLETED',
|
||||
Confirmed = 'CONFIRMED',
|
||||
InProgress = 'IN_PROGRESS',
|
||||
ManagerBlocked = 'MANAGER_BLOCKED',
|
||||
ManagerProcessing = 'MANAGER_PROCESSING',
|
||||
ManagerRejected = 'MANAGER_REJECTED',
|
||||
New = 'NEW',
|
||||
WaitingDoubleConfirm = 'WAITING_DOUBLE_CONFIRM'
|
||||
}
|
||||
|
||||
export type OrderStatusEvent = {
|
||||
__typename?: 'OrderStatusEvent';
|
||||
actorUserId: Scalars['ID']['output'];
|
||||
createdAt: Scalars['DateTime']['output'];
|
||||
id: Scalars['ID']['output'];
|
||||
note?: Maybe<Scalars['String']['output']>;
|
||||
status: OrderStatus;
|
||||
};
|
||||
|
||||
export type Product = {
|
||||
__typename?: 'Product';
|
||||
availableInWarehouses: Array<ProductWarehouseBalance>;
|
||||
description?: Maybe<Scalars['String']['output']>;
|
||||
id: Scalars['ID']['output'];
|
||||
isActive: Scalars['Boolean']['output'];
|
||||
isCustomizable: Scalars['Boolean']['output'];
|
||||
name: Scalars['String']['output'];
|
||||
sku: Scalars['String']['output'];
|
||||
};
|
||||
|
||||
export type ProductWarehouseBalance = {
|
||||
__typename?: 'ProductWarehouseBalance';
|
||||
availableQty: Scalars['Float']['output'];
|
||||
warehouse: Warehouse;
|
||||
};
|
||||
|
||||
export type Query = {
|
||||
__typename?: 'Query';
|
||||
clientProducts: Array<Product>;
|
||||
healthcheck: Scalars['String']['output'];
|
||||
managerOrders: Array<Order>;
|
||||
me?: Maybe<User>;
|
||||
myCurrentOrders: Array<Order>;
|
||||
myOrders: Array<Order>;
|
||||
referralStats: ReferralStats;
|
||||
registrationRequests: Array<RegistrationRequest>;
|
||||
};
|
||||
|
||||
|
||||
export type QueryManagerOrdersArgs = {
|
||||
status?: InputMaybe<OrderStatus>;
|
||||
};
|
||||
|
||||
|
||||
export type QueryRegistrationRequestsArgs = {
|
||||
status?: InputMaybe<RegistrationStatus>;
|
||||
};
|
||||
|
||||
export type ReadyOrderItemInput = {
|
||||
productId: Scalars['ID']['input'];
|
||||
quantity: Scalars['Float']['input'];
|
||||
};
|
||||
|
||||
export type ReferralLink = {
|
||||
__typename?: 'ReferralLink';
|
||||
createdAt: Scalars['DateTime']['output'];
|
||||
id: Scalars['ID']['output'];
|
||||
refereeId: Scalars['ID']['output'];
|
||||
referrerId: Scalars['ID']['output'];
|
||||
};
|
||||
|
||||
export type ReferralStats = {
|
||||
__typename?: 'ReferralStats';
|
||||
availableBalance: Scalars['Float']['output'];
|
||||
pendingWithdrawals: Array<RewardWithdrawalRequest>;
|
||||
referralsCount: Scalars['Int']['output'];
|
||||
referrerId: Scalars['ID']['output'];
|
||||
transactions: Array<BonusTransaction>;
|
||||
};
|
||||
|
||||
export type RegisterSelfInput = {
|
||||
companyName: Scalars['String']['input'];
|
||||
contactName: Scalars['String']['input'];
|
||||
email: Scalars['String']['input'];
|
||||
inn?: InputMaybe<Scalars['String']['input']>;
|
||||
};
|
||||
|
||||
export type RegistrationRequest = {
|
||||
__typename?: 'RegistrationRequest';
|
||||
companyName: Scalars['String']['output'];
|
||||
contactName: Scalars['String']['output'];
|
||||
createdAt: Scalars['DateTime']['output'];
|
||||
email: Scalars['String']['output'];
|
||||
id: Scalars['ID']['output'];
|
||||
inn?: Maybe<Scalars['String']['output']>;
|
||||
rejectionReason?: Maybe<Scalars['String']['output']>;
|
||||
reviewedById?: Maybe<Scalars['ID']['output']>;
|
||||
status: RegistrationStatus;
|
||||
updatedAt: Scalars['DateTime']['output'];
|
||||
};
|
||||
|
||||
export enum RegistrationStatus {
|
||||
Approved = 'APPROVED',
|
||||
Pending = 'PENDING',
|
||||
Rejected = 'REJECTED'
|
||||
}
|
||||
|
||||
export type RequestRewardWithdrawalInput = {
|
||||
amount: Scalars['Float']['input'];
|
||||
};
|
||||
|
||||
export type ReviewRegistrationRequestInput = {
|
||||
decision: Decision;
|
||||
rejectionReason?: InputMaybe<Scalars['String']['input']>;
|
||||
requestId: Scalars['ID']['input'];
|
||||
};
|
||||
|
||||
export type ReviewRewardWithdrawalInput = {
|
||||
decision: Decision;
|
||||
reviewComment?: InputMaybe<Scalars['String']['input']>;
|
||||
withdrawalId: Scalars['ID']['input'];
|
||||
};
|
||||
|
||||
export type RewardWithdrawalRequest = {
|
||||
__typename?: 'RewardWithdrawalRequest';
|
||||
amount: Scalars['Float']['output'];
|
||||
createdAt: Scalars['DateTime']['output'];
|
||||
id: Scalars['ID']['output'];
|
||||
requesterId: Scalars['ID']['output'];
|
||||
reviewComment?: Maybe<Scalars['String']['output']>;
|
||||
reviewedById?: Maybe<Scalars['ID']['output']>;
|
||||
status: WithdrawalStatus;
|
||||
updatedAt: Scalars['DateTime']['output'];
|
||||
};
|
||||
|
||||
export type SetOrderOfferInput = {
|
||||
deliveryFee: Scalars['Float']['input'];
|
||||
deliveryTerms: Scalars['String']['input'];
|
||||
orderId: Scalars['ID']['input'];
|
||||
totalPrice: Scalars['Float']['input'];
|
||||
};
|
||||
|
||||
export type SubmitCalculationOrderInput = {
|
||||
parameters: Scalars['JSON']['input'];
|
||||
productName: Scalars['String']['input'];
|
||||
quantity: Scalars['Float']['input'];
|
||||
};
|
||||
|
||||
export type SubmitReadyOrderInput = {
|
||||
items: Array<ReadyOrderItemInput>;
|
||||
};
|
||||
|
||||
export type User = {
|
||||
__typename?: 'User';
|
||||
company?: Maybe<Company>;
|
||||
email: Scalars['String']['output'];
|
||||
fullName: Scalars['String']['output'];
|
||||
id: Scalars['ID']['output'];
|
||||
role: UserRole;
|
||||
};
|
||||
|
||||
export enum UserRole {
|
||||
Client = 'CLIENT',
|
||||
Manager = 'MANAGER'
|
||||
}
|
||||
|
||||
export type Warehouse = {
|
||||
__typename?: 'Warehouse';
|
||||
code: Scalars['String']['output'];
|
||||
id: Scalars['ID']['output'];
|
||||
name: Scalars['String']['output'];
|
||||
};
|
||||
|
||||
export enum WithdrawalStatus {
|
||||
Approved = 'APPROVED',
|
||||
Pending = 'PENDING',
|
||||
Rejected = 'REJECTED'
|
||||
}
|
||||
|
||||
export type RegisterSelfMutationVariables = Exact<{
|
||||
input: RegisterSelfInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type RegisterSelfMutation = { __typename?: 'Mutation', registerSelf: { __typename?: 'RegistrationRequest', id: string, companyName: string, contactName: string, email: string, status: RegistrationStatus, createdAt: any } };
|
||||
|
||||
export type ClientProductsQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type ClientProductsQuery = { __typename?: 'Query', clientProducts: Array<{ __typename?: 'Product', id: string, sku: string, name: string, description?: string | null, isCustomizable: boolean, availableInWarehouses: Array<{ __typename?: 'ProductWarehouseBalance', availableQty: number, warehouse: { __typename?: 'Warehouse', id: string, code: string, name: string } }> }> };
|
||||
|
||||
export type MyCurrentOrdersQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type MyCurrentOrdersQuery = { __typename?: 'Query', myCurrentOrders: Array<{ __typename?: 'Order', id: string, code: string, kind: OrderKind, status: OrderStatus, createdAt: any, items: Array<{ __typename?: 'OrderItem', id: string, productName: string, quantity: number }> }> };
|
||||
|
||||
export type MyOrdersQueryVariables = Exact<{ [key: string]: never; }>;
|
||||
|
||||
|
||||
export type MyOrdersQuery = { __typename?: 'Query', myOrders: Array<{ __typename?: 'Order', id: string, code: string, kind: OrderKind, status: OrderStatus, totalPrice?: number | null, deliveryTerms?: string | null, createdAt: any, items: Array<{ __typename?: 'OrderItem', id: string, productName: string, quantity: number }> }> };
|
||||
|
||||
export type SubmitCalculationOrderMutationVariables = Exact<{
|
||||
input: SubmitCalculationOrderInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type SubmitCalculationOrderMutation = { __typename?: 'Mutation', submitCalculationOrder: { __typename?: 'Order', id: string, code: string, status: OrderStatus, createdAt: any } };
|
||||
|
||||
export type SubmitReadyOrderMutationVariables = Exact<{
|
||||
input: SubmitReadyOrderInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type SubmitReadyOrderMutation = { __typename?: 'Mutation', submitReadyOrder: { __typename?: 'Order', id: string, code: string, status: OrderStatus, createdAt: any } };
|
||||
|
||||
export type ConnectMessengerMutationVariables = Exact<{
|
||||
input: ConnectMessengerInput;
|
||||
}>;
|
||||
|
||||
|
||||
export type ConnectMessengerMutation = { __typename?: 'Mutation', connectMessenger: { __typename?: 'MessengerConnection', id: string, type: MessengerType, channelId: string, isActive: boolean } };
|
||||
|
||||
|
||||
export const RegisterSelfDocument = gql`
|
||||
mutation RegisterSelf($input: RegisterSelfInput!) {
|
||||
registerSelf(input: $input) {
|
||||
id
|
||||
companyName
|
||||
contactName
|
||||
email
|
||||
status
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useRegisterSelfMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useRegisterSelfMutation` within a Vue component and pass it any options that fit your needs.
|
||||
* When your component renders, `useRegisterSelfMutation` returns an object that includes:
|
||||
* - A mutate function that you can call at any time to execute the mutation
|
||||
* - Several other properties: https://v4.apollo.vuejs.org/api/use-mutation.html#return
|
||||
*
|
||||
* @param options that will be passed into the mutation, supported options are listed on: https://v4.apollo.vuejs.org/guide-composable/mutation.html#options;
|
||||
*
|
||||
* @example
|
||||
* const { mutate, loading, error, onDone } = useRegisterSelfMutation({
|
||||
* variables: {
|
||||
* input: // value for 'input'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useRegisterSelfMutation(options: VueApolloComposable.UseMutationOptions<RegisterSelfMutation, RegisterSelfMutationVariables> | ReactiveFunction<VueApolloComposable.UseMutationOptions<RegisterSelfMutation, RegisterSelfMutationVariables>> = {}) {
|
||||
return VueApolloComposable.useMutation<RegisterSelfMutation, RegisterSelfMutationVariables>(RegisterSelfDocument, options);
|
||||
}
|
||||
export type RegisterSelfMutationCompositionFunctionResult = VueApolloComposable.UseMutationReturn<RegisterSelfMutation, RegisterSelfMutationVariables>;
|
||||
export const ClientProductsDocument = gql`
|
||||
query ClientProducts {
|
||||
clientProducts {
|
||||
id
|
||||
sku
|
||||
name
|
||||
description
|
||||
isCustomizable
|
||||
availableInWarehouses {
|
||||
availableQty
|
||||
warehouse {
|
||||
id
|
||||
code
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useClientProductsQuery__
|
||||
*
|
||||
* To run a query within a Vue component, call `useClientProductsQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useClientProductsQuery` returns an object from Apollo Client that contains result, loading and error properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param options that will be passed into the query, supported options are listed on: https://v4.apollo.vuejs.org/guide-composable/query.html#options;
|
||||
*
|
||||
* @example
|
||||
* const { result, loading, error } = useClientProductsQuery();
|
||||
*/
|
||||
export function useClientProductsQuery(options: VueApolloComposable.UseQueryOptions<ClientProductsQuery, ClientProductsQueryVariables> | VueCompositionApi.Ref<VueApolloComposable.UseQueryOptions<ClientProductsQuery, ClientProductsQueryVariables>> | ReactiveFunction<VueApolloComposable.UseQueryOptions<ClientProductsQuery, ClientProductsQueryVariables>> = {}) {
|
||||
return VueApolloComposable.useQuery<ClientProductsQuery, ClientProductsQueryVariables>(ClientProductsDocument, {}, options);
|
||||
}
|
||||
export function useClientProductsLazyQuery(options: VueApolloComposable.UseQueryOptions<ClientProductsQuery, ClientProductsQueryVariables> | VueCompositionApi.Ref<VueApolloComposable.UseQueryOptions<ClientProductsQuery, ClientProductsQueryVariables>> | ReactiveFunction<VueApolloComposable.UseQueryOptions<ClientProductsQuery, ClientProductsQueryVariables>> = {}) {
|
||||
return VueApolloComposable.useLazyQuery<ClientProductsQuery, ClientProductsQueryVariables>(ClientProductsDocument, {}, options);
|
||||
}
|
||||
export type ClientProductsQueryCompositionFunctionResult = VueApolloComposable.UseQueryReturn<ClientProductsQuery, ClientProductsQueryVariables>;
|
||||
export const MyCurrentOrdersDocument = gql`
|
||||
query MyCurrentOrders {
|
||||
myCurrentOrders {
|
||||
id
|
||||
code
|
||||
kind
|
||||
status
|
||||
createdAt
|
||||
items {
|
||||
id
|
||||
productName
|
||||
quantity
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useMyCurrentOrdersQuery__
|
||||
*
|
||||
* To run a query within a Vue component, call `useMyCurrentOrdersQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useMyCurrentOrdersQuery` returns an object from Apollo Client that contains result, loading and error properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param options that will be passed into the query, supported options are listed on: https://v4.apollo.vuejs.org/guide-composable/query.html#options;
|
||||
*
|
||||
* @example
|
||||
* const { result, loading, error } = useMyCurrentOrdersQuery();
|
||||
*/
|
||||
export function useMyCurrentOrdersQuery(options: VueApolloComposable.UseQueryOptions<MyCurrentOrdersQuery, MyCurrentOrdersQueryVariables> | VueCompositionApi.Ref<VueApolloComposable.UseQueryOptions<MyCurrentOrdersQuery, MyCurrentOrdersQueryVariables>> | ReactiveFunction<VueApolloComposable.UseQueryOptions<MyCurrentOrdersQuery, MyCurrentOrdersQueryVariables>> = {}) {
|
||||
return VueApolloComposable.useQuery<MyCurrentOrdersQuery, MyCurrentOrdersQueryVariables>(MyCurrentOrdersDocument, {}, options);
|
||||
}
|
||||
export function useMyCurrentOrdersLazyQuery(options: VueApolloComposable.UseQueryOptions<MyCurrentOrdersQuery, MyCurrentOrdersQueryVariables> | VueCompositionApi.Ref<VueApolloComposable.UseQueryOptions<MyCurrentOrdersQuery, MyCurrentOrdersQueryVariables>> | ReactiveFunction<VueApolloComposable.UseQueryOptions<MyCurrentOrdersQuery, MyCurrentOrdersQueryVariables>> = {}) {
|
||||
return VueApolloComposable.useLazyQuery<MyCurrentOrdersQuery, MyCurrentOrdersQueryVariables>(MyCurrentOrdersDocument, {}, options);
|
||||
}
|
||||
export type MyCurrentOrdersQueryCompositionFunctionResult = VueApolloComposable.UseQueryReturn<MyCurrentOrdersQuery, MyCurrentOrdersQueryVariables>;
|
||||
export const MyOrdersDocument = gql`
|
||||
query MyOrders {
|
||||
myOrders {
|
||||
id
|
||||
code
|
||||
kind
|
||||
status
|
||||
totalPrice
|
||||
deliveryTerms
|
||||
createdAt
|
||||
items {
|
||||
id
|
||||
productName
|
||||
quantity
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useMyOrdersQuery__
|
||||
*
|
||||
* To run a query within a Vue component, call `useMyOrdersQuery` and pass it any options that fit your needs.
|
||||
* When your component renders, `useMyOrdersQuery` returns an object from Apollo Client that contains result, loading and error properties
|
||||
* you can use to render your UI.
|
||||
*
|
||||
* @param options that will be passed into the query, supported options are listed on: https://v4.apollo.vuejs.org/guide-composable/query.html#options;
|
||||
*
|
||||
* @example
|
||||
* const { result, loading, error } = useMyOrdersQuery();
|
||||
*/
|
||||
export function useMyOrdersQuery(options: VueApolloComposable.UseQueryOptions<MyOrdersQuery, MyOrdersQueryVariables> | VueCompositionApi.Ref<VueApolloComposable.UseQueryOptions<MyOrdersQuery, MyOrdersQueryVariables>> | ReactiveFunction<VueApolloComposable.UseQueryOptions<MyOrdersQuery, MyOrdersQueryVariables>> = {}) {
|
||||
return VueApolloComposable.useQuery<MyOrdersQuery, MyOrdersQueryVariables>(MyOrdersDocument, {}, options);
|
||||
}
|
||||
export function useMyOrdersLazyQuery(options: VueApolloComposable.UseQueryOptions<MyOrdersQuery, MyOrdersQueryVariables> | VueCompositionApi.Ref<VueApolloComposable.UseQueryOptions<MyOrdersQuery, MyOrdersQueryVariables>> | ReactiveFunction<VueApolloComposable.UseQueryOptions<MyOrdersQuery, MyOrdersQueryVariables>> = {}) {
|
||||
return VueApolloComposable.useLazyQuery<MyOrdersQuery, MyOrdersQueryVariables>(MyOrdersDocument, {}, options);
|
||||
}
|
||||
export type MyOrdersQueryCompositionFunctionResult = VueApolloComposable.UseQueryReturn<MyOrdersQuery, MyOrdersQueryVariables>;
|
||||
export const SubmitCalculationOrderDocument = gql`
|
||||
mutation SubmitCalculationOrder($input: SubmitCalculationOrderInput!) {
|
||||
submitCalculationOrder(input: $input) {
|
||||
id
|
||||
code
|
||||
status
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useSubmitCalculationOrderMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useSubmitCalculationOrderMutation` within a Vue component and pass it any options that fit your needs.
|
||||
* When your component renders, `useSubmitCalculationOrderMutation` returns an object that includes:
|
||||
* - A mutate function that you can call at any time to execute the mutation
|
||||
* - Several other properties: https://v4.apollo.vuejs.org/api/use-mutation.html#return
|
||||
*
|
||||
* @param options that will be passed into the mutation, supported options are listed on: https://v4.apollo.vuejs.org/guide-composable/mutation.html#options;
|
||||
*
|
||||
* @example
|
||||
* const { mutate, loading, error, onDone } = useSubmitCalculationOrderMutation({
|
||||
* variables: {
|
||||
* input: // value for 'input'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useSubmitCalculationOrderMutation(options: VueApolloComposable.UseMutationOptions<SubmitCalculationOrderMutation, SubmitCalculationOrderMutationVariables> | ReactiveFunction<VueApolloComposable.UseMutationOptions<SubmitCalculationOrderMutation, SubmitCalculationOrderMutationVariables>> = {}) {
|
||||
return VueApolloComposable.useMutation<SubmitCalculationOrderMutation, SubmitCalculationOrderMutationVariables>(SubmitCalculationOrderDocument, options);
|
||||
}
|
||||
export type SubmitCalculationOrderMutationCompositionFunctionResult = VueApolloComposable.UseMutationReturn<SubmitCalculationOrderMutation, SubmitCalculationOrderMutationVariables>;
|
||||
export const SubmitReadyOrderDocument = gql`
|
||||
mutation SubmitReadyOrder($input: SubmitReadyOrderInput!) {
|
||||
submitReadyOrder(input: $input) {
|
||||
id
|
||||
code
|
||||
status
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useSubmitReadyOrderMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useSubmitReadyOrderMutation` within a Vue component and pass it any options that fit your needs.
|
||||
* When your component renders, `useSubmitReadyOrderMutation` returns an object that includes:
|
||||
* - A mutate function that you can call at any time to execute the mutation
|
||||
* - Several other properties: https://v4.apollo.vuejs.org/api/use-mutation.html#return
|
||||
*
|
||||
* @param options that will be passed into the mutation, supported options are listed on: https://v4.apollo.vuejs.org/guide-composable/mutation.html#options;
|
||||
*
|
||||
* @example
|
||||
* const { mutate, loading, error, onDone } = useSubmitReadyOrderMutation({
|
||||
* variables: {
|
||||
* input: // value for 'input'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useSubmitReadyOrderMutation(options: VueApolloComposable.UseMutationOptions<SubmitReadyOrderMutation, SubmitReadyOrderMutationVariables> | ReactiveFunction<VueApolloComposable.UseMutationOptions<SubmitReadyOrderMutation, SubmitReadyOrderMutationVariables>> = {}) {
|
||||
return VueApolloComposable.useMutation<SubmitReadyOrderMutation, SubmitReadyOrderMutationVariables>(SubmitReadyOrderDocument, options);
|
||||
}
|
||||
export type SubmitReadyOrderMutationCompositionFunctionResult = VueApolloComposable.UseMutationReturn<SubmitReadyOrderMutation, SubmitReadyOrderMutationVariables>;
|
||||
export const ConnectMessengerDocument = gql`
|
||||
mutation ConnectMessenger($input: ConnectMessengerInput!) {
|
||||
connectMessenger(input: $input) {
|
||||
id
|
||||
type
|
||||
channelId
|
||||
isActive
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
/**
|
||||
* __useConnectMessengerMutation__
|
||||
*
|
||||
* To run a mutation, you first call `useConnectMessengerMutation` within a Vue component and pass it any options that fit your needs.
|
||||
* When your component renders, `useConnectMessengerMutation` returns an object that includes:
|
||||
* - A mutate function that you can call at any time to execute the mutation
|
||||
* - Several other properties: https://v4.apollo.vuejs.org/api/use-mutation.html#return
|
||||
*
|
||||
* @param options that will be passed into the mutation, supported options are listed on: https://v4.apollo.vuejs.org/guide-composable/mutation.html#options;
|
||||
*
|
||||
* @example
|
||||
* const { mutate, loading, error, onDone } = useConnectMessengerMutation({
|
||||
* variables: {
|
||||
* input: // value for 'input'
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
export function useConnectMessengerMutation(options: VueApolloComposable.UseMutationOptions<ConnectMessengerMutation, ConnectMessengerMutationVariables> | ReactiveFunction<VueApolloComposable.UseMutationOptions<ConnectMessengerMutation, ConnectMessengerMutationVariables>> = {}) {
|
||||
return VueApolloComposable.useMutation<ConnectMessengerMutation, ConnectMessengerMutationVariables>(ConnectMessengerDocument, options);
|
||||
}
|
||||
export type ConnectMessengerMutationCompositionFunctionResult = VueApolloComposable.UseMutationReturn<ConnectMessengerMutation, ConnectMessengerMutationVariables>;
|
||||
5
app/composables/useGqlClient.ts
Normal file
5
app/composables/useGqlClient.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
import type { ApolloClient, NormalizedCacheObject } from '@apollo/client/core';
|
||||
|
||||
export function useGqlClient(): ApolloClient<NormalizedCacheObject> {
|
||||
return useNuxtApp().$apollo as ApolloClient<NormalizedCacheObject>;
|
||||
}
|
||||
73
app/pages/cart.vue
Normal file
73
app/pages/cart.vue
Normal file
@@ -0,0 +1,73 @@
|
||||
<script setup lang="ts">
|
||||
import { useMutation } from '@vue/apollo-composable';
|
||||
import { SubmitCalculationOrderDocument } from '~/composables/graphql/generated';
|
||||
|
||||
const productName = ref('');
|
||||
const quantity = ref(1);
|
||||
const width = ref(100);
|
||||
const thickness = ref(50);
|
||||
const color = ref('прозрачный');
|
||||
|
||||
const { mutate, loading, onDone, onError } = useMutation(SubmitCalculationOrderDocument);
|
||||
const success = ref('');
|
||||
const errorMessage = ref('');
|
||||
|
||||
onDone((result) => {
|
||||
success.value = `Заявка ${result.data?.submitCalculationOrder.code} отправлена`;
|
||||
errorMessage.value = '';
|
||||
});
|
||||
|
||||
onError((error) => {
|
||||
errorMessage.value = error.message;
|
||||
success.value = '';
|
||||
});
|
||||
|
||||
function submit() {
|
||||
mutate({
|
||||
input: {
|
||||
productName: productName.value,
|
||||
quantity: Number(quantity.value),
|
||||
parameters: {
|
||||
width: Number(width.value),
|
||||
thickness: Number(thickness.value),
|
||||
color: color.value,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="space-y-4 max-w-2xl">
|
||||
<h1 class="text-2xl font-bold">Корзина / заявка на расчет</h1>
|
||||
<div class="card bg-base-100 border border-base-300">
|
||||
<div class="card-body space-y-3">
|
||||
<label class="form-control">
|
||||
<span class="label-text">Название позиции</span>
|
||||
<input v-model="productName" type="text" class="input input-bordered" />
|
||||
</label>
|
||||
<label class="form-control">
|
||||
<span class="label-text">Количество</span>
|
||||
<input v-model="quantity" type="number" min="1" class="input input-bordered" />
|
||||
</label>
|
||||
<label class="form-control">
|
||||
<span class="label-text">Ширина</span>
|
||||
<input v-model="width" type="number" min="1" class="input input-bordered" />
|
||||
</label>
|
||||
<label class="form-control">
|
||||
<span class="label-text">Толщина</span>
|
||||
<input v-model="thickness" type="number" min="1" class="input input-bordered" />
|
||||
</label>
|
||||
<label class="form-control">
|
||||
<span class="label-text">Цвет</span>
|
||||
<input v-model="color" type="text" class="input input-bordered" />
|
||||
</label>
|
||||
|
||||
<button class="btn btn-primary" :disabled="loading" @click="submit">Отправить менеджеру</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="success" class="alert alert-success">{{ success }}</div>
|
||||
<div v-if="errorMessage" class="alert alert-error">{{ errorMessage }}</div>
|
||||
</section>
|
||||
</template>
|
||||
12
app/pages/index.vue
Normal file
12
app/pages/index.vue
Normal file
@@ -0,0 +1,12 @@
|
||||
<template>
|
||||
<section class="space-y-6">
|
||||
<h1 class="text-3xl font-bold">Личный кабинет клиента</h1>
|
||||
<p class="text-base-content/80">Основные действия по спецификации: витрина, корзина, заказы и профиль с каналами уведомлений.</p>
|
||||
<div class="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
|
||||
<NuxtLink to="/products" class="card bg-base-100 border border-base-300 shadow-sm"><div class="card-body"><h2 class="card-title">Товары</h2></div></NuxtLink>
|
||||
<NuxtLink to="/cart" class="card bg-base-100 border border-base-300 shadow-sm"><div class="card-body"><h2 class="card-title">Корзина</h2></div></NuxtLink>
|
||||
<NuxtLink to="/orders" class="card bg-base-100 border border-base-300 shadow-sm"><div class="card-body"><h2 class="card-title">Заказы</h2></div></NuxtLink>
|
||||
<NuxtLink to="/profile" class="card bg-base-100 border border-base-300 shadow-sm"><div class="card-body"><h2 class="card-title">Профиль</h2></div></NuxtLink>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
46
app/pages/orders.vue
Normal file
46
app/pages/orders.vue
Normal file
@@ -0,0 +1,46 @@
|
||||
<script setup lang="ts">
|
||||
import { useQuery } from '@vue/apollo-composable';
|
||||
import OrderStatusBadge from '~/components/orders/OrderStatusBadge.vue';
|
||||
import { MyCurrentOrdersDocument, MyOrdersDocument } from '~/composables/graphql/generated';
|
||||
|
||||
const currentOrders = useQuery(MyCurrentOrdersDocument);
|
||||
const allOrders = useQuery(MyOrdersDocument);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="space-y-8">
|
||||
<h1 class="text-2xl font-bold">Мои заказы</h1>
|
||||
|
||||
<div class="space-y-3">
|
||||
<h2 class="text-xl font-semibold">Текущие</h2>
|
||||
<div v-if="currentOrders.loading.value" class="alert">Загрузка...</div>
|
||||
<div v-else class="space-y-3">
|
||||
<article v-for="order in currentOrders.result.value?.myCurrentOrders ?? []" :key="order.id" class="card bg-base-100 border border-base-300">
|
||||
<div class="card-body gap-2">
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="font-semibold">{{ order.code }}</h3>
|
||||
<OrderStatusBadge :status="order.status" />
|
||||
</div>
|
||||
<ul class="text-sm">
|
||||
<li v-for="item in order.items" :key="item.id">{{ item.productName }} × {{ item.quantity }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="space-y-3">
|
||||
<h2 class="text-xl font-semibold">Все</h2>
|
||||
<article v-for="order in allOrders.result.value?.myOrders ?? []" :key="order.id" class="card bg-base-100 border border-base-300">
|
||||
<div class="card-body gap-2">
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="font-semibold">{{ order.code }}</h3>
|
||||
<OrderStatusBadge :status="order.status" />
|
||||
</div>
|
||||
<p class="text-sm">Условия доставки: {{ order.deliveryTerms || 'ожидает обработки менеджером' }}</p>
|
||||
<p class="text-sm">Итого: {{ order.totalPrice ?? 'после обработки менеджером' }}</p>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
26
app/pages/products.vue
Normal file
26
app/pages/products.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
<script setup lang="ts">
|
||||
import { useQuery } from '@vue/apollo-composable';
|
||||
import { ClientProductsDocument } from '~/composables/graphql/generated';
|
||||
|
||||
const { result, loading, error } = useQuery(ClientProductsDocument);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="space-y-4">
|
||||
<h1 class="text-2xl font-bold">Витрина товаров</h1>
|
||||
<div v-if="loading" class="alert">Загрузка...</div>
|
||||
<div v-else-if="error" class="alert alert-error">{{ error.message }}</div>
|
||||
<div v-else class="grid gap-4 lg:grid-cols-2">
|
||||
<article v-for="product in result?.clientProducts ?? []" :key="product.id" class="card bg-base-100 border border-base-300">
|
||||
<div class="card-body gap-2">
|
||||
<h2 class="card-title">{{ product.name }}</h2>
|
||||
<p class="text-sm opacity-80">{{ product.description }}</p>
|
||||
<p class="text-xs">SKU: {{ product.sku }}</p>
|
||||
<ul class="text-sm space-y-1">
|
||||
<li v-for="stock in product.availableInWarehouses" :key="stock.warehouse.id">{{ stock.warehouse.name }}: {{ stock.availableQty }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
71
app/pages/profile.vue
Normal file
71
app/pages/profile.vue
Normal file
@@ -0,0 +1,71 @@
|
||||
<script setup lang="ts">
|
||||
import { useMutation } from '@vue/apollo-composable';
|
||||
import { ConnectMessengerDocument, RegisterSelfDocument } from '~/composables/graphql/generated';
|
||||
|
||||
const companyName = ref('');
|
||||
const inn = ref('');
|
||||
const contactName = ref('');
|
||||
const email = ref('');
|
||||
const channelId = ref('');
|
||||
const channelType = ref<'TELEGRAM' | 'MAX'>('TELEGRAM');
|
||||
|
||||
const registerMutation = useMutation(RegisterSelfDocument);
|
||||
const messengerMutation = useMutation(ConnectMessengerDocument);
|
||||
|
||||
const message = ref('');
|
||||
|
||||
function register() {
|
||||
registerMutation.mutate({
|
||||
input: {
|
||||
companyName: companyName.value,
|
||||
inn: inn.value || null,
|
||||
contactName: contactName.value,
|
||||
email: email.value,
|
||||
},
|
||||
}).then(() => {
|
||||
message.value = 'Заявка на регистрацию отправлена менеджеру';
|
||||
});
|
||||
}
|
||||
|
||||
function connectMessenger() {
|
||||
messengerMutation.mutate({
|
||||
input: {
|
||||
type: channelType.value,
|
||||
channelId: channelId.value,
|
||||
},
|
||||
}).then(() => {
|
||||
message.value = 'Канал уведомлений подключен';
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<section class="space-y-6 max-w-2xl">
|
||||
<h1 class="text-2xl font-bold">Профиль и каналы уведомлений</h1>
|
||||
|
||||
<div class="card bg-base-100 border border-base-300">
|
||||
<div class="card-body space-y-3">
|
||||
<h2 class="card-title">Самостоятельная регистрация</h2>
|
||||
<input v-model="companyName" type="text" placeholder="Компания" class="input input-bordered" />
|
||||
<input v-model="inn" type="text" placeholder="ИНН" class="input input-bordered" />
|
||||
<input v-model="contactName" type="text" placeholder="Контактное лицо" class="input input-bordered" />
|
||||
<input v-model="email" type="email" placeholder="Email" class="input input-bordered" />
|
||||
<button class="btn btn-primary" @click="register">Отправить заявку</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card bg-base-100 border border-base-300">
|
||||
<div class="card-body space-y-3">
|
||||
<h2 class="card-title">Подключение мессенджера</h2>
|
||||
<select v-model="channelType" class="select select-bordered">
|
||||
<option value="TELEGRAM">Telegram</option>
|
||||
<option value="MAX">Max</option>
|
||||
</select>
|
||||
<input v-model="channelId" type="text" placeholder="ID канала" class="input input-bordered" />
|
||||
<button class="btn btn-secondary" @click="connectMessenger">Подключить канал</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="message" class="alert alert-success">{{ message }}</div>
|
||||
</section>
|
||||
</template>
|
||||
23
app/plugins/apollo.ts
Normal file
23
app/plugins/apollo.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { ApolloClient, HttpLink, InMemoryCache } from '@apollo/client/core';
|
||||
import { provideApolloClient } from '@vue/apollo-composable';
|
||||
|
||||
export default defineNuxtPlugin(() => {
|
||||
const config = useRuntimeConfig();
|
||||
|
||||
const client = new ApolloClient({
|
||||
link: new HttpLink({
|
||||
uri: config.public.graphqlEndpoint,
|
||||
fetch,
|
||||
}),
|
||||
cache: new InMemoryCache(),
|
||||
connectToDevTools: import.meta.dev,
|
||||
});
|
||||
|
||||
provideApolloClient(client);
|
||||
|
||||
return {
|
||||
provide: {
|
||||
apollo: client,
|
||||
},
|
||||
};
|
||||
});
|
||||
18
app/plugins/sentry.client.ts
Normal file
18
app/plugins/sentry.client.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import * as Sentry from '@sentry/vue';
|
||||
|
||||
export default defineNuxtPlugin((nuxtApp) => {
|
||||
const config = useRuntimeConfig();
|
||||
const dsn = config.public.sentryDsn;
|
||||
|
||||
if (!dsn) {
|
||||
return;
|
||||
}
|
||||
|
||||
Sentry.init({
|
||||
app: nuxtApp.vueApp,
|
||||
dsn,
|
||||
environment: config.public.sentryEnvironment,
|
||||
release: config.public.sentryRelease,
|
||||
tracesSampleRate: 0.1,
|
||||
});
|
||||
});
|
||||
18
codegen.ts
Normal file
18
codegen.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import type { CodegenConfig } from '@graphql-codegen/cli';
|
||||
|
||||
const config: CodegenConfig = {
|
||||
schema: './graphql/schema.graphql',
|
||||
documents: ['./graphql/operations/**/*.graphql'],
|
||||
generates: {
|
||||
'./app/composables/graphql/generated.ts': {
|
||||
plugins: ['typescript', 'typescript-operations', 'typescript-vue-apollo'],
|
||||
config: {
|
||||
withCompositionFunctions: true,
|
||||
vueApolloComposableImportFrom: '@vue/apollo-composable',
|
||||
useTypeImports: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default config;
|
||||
6
eslint.config.mjs
Normal file
6
eslint.config.mjs
Normal file
@@ -0,0 +1,6 @@
|
||||
// @ts-check
|
||||
import withNuxt from './.nuxt/eslint.config.mjs'
|
||||
|
||||
export default withNuxt(
|
||||
// Your custom configs here
|
||||
)
|
||||
10
graphql/operations/auth/register-self.graphql
Normal file
10
graphql/operations/auth/register-self.graphql
Normal file
@@ -0,0 +1,10 @@
|
||||
mutation RegisterSelf($input: RegisterSelfInput!) {
|
||||
registerSelf(input: $input) {
|
||||
id
|
||||
companyName
|
||||
contactName
|
||||
email
|
||||
status
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
17
graphql/operations/catalog/client-products.graphql
Normal file
17
graphql/operations/catalog/client-products.graphql
Normal file
@@ -0,0 +1,17 @@
|
||||
query ClientProducts {
|
||||
clientProducts {
|
||||
id
|
||||
sku
|
||||
name
|
||||
description
|
||||
isCustomizable
|
||||
availableInWarehouses {
|
||||
availableQty
|
||||
warehouse {
|
||||
id
|
||||
code
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
14
graphql/operations/orders/my-current-orders.graphql
Normal file
14
graphql/operations/orders/my-current-orders.graphql
Normal file
@@ -0,0 +1,14 @@
|
||||
query MyCurrentOrders {
|
||||
myCurrentOrders {
|
||||
id
|
||||
code
|
||||
kind
|
||||
status
|
||||
createdAt
|
||||
items {
|
||||
id
|
||||
productName
|
||||
quantity
|
||||
}
|
||||
}
|
||||
}
|
||||
16
graphql/operations/orders/my-orders.graphql
Normal file
16
graphql/operations/orders/my-orders.graphql
Normal file
@@ -0,0 +1,16 @@
|
||||
query MyOrders {
|
||||
myOrders {
|
||||
id
|
||||
code
|
||||
kind
|
||||
status
|
||||
totalPrice
|
||||
deliveryTerms
|
||||
createdAt
|
||||
items {
|
||||
id
|
||||
productName
|
||||
quantity
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
mutation SubmitCalculationOrder($input: SubmitCalculationOrderInput!) {
|
||||
submitCalculationOrder(input: $input) {
|
||||
id
|
||||
code
|
||||
status
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
8
graphql/operations/orders/submit-ready-order.graphql
Normal file
8
graphql/operations/orders/submit-ready-order.graphql
Normal file
@@ -0,0 +1,8 @@
|
||||
mutation SubmitReadyOrder($input: SubmitReadyOrderInput!) {
|
||||
submitReadyOrder(input: $input) {
|
||||
id
|
||||
code
|
||||
status
|
||||
createdAt
|
||||
}
|
||||
}
|
||||
8
graphql/operations/profile/connect-messenger.graphql
Normal file
8
graphql/operations/profile/connect-messenger.graphql
Normal file
@@ -0,0 +1,8 @@
|
||||
mutation ConnectMessenger($input: ConnectMessengerInput!) {
|
||||
connectMessenger(input: $input) {
|
||||
id
|
||||
type
|
||||
channelId
|
||||
isActive
|
||||
}
|
||||
}
|
||||
294
graphql/schema.graphql
Normal file
294
graphql/schema.graphql
Normal file
@@ -0,0 +1,294 @@
|
||||
scalar DateTime
|
||||
scalar JSON
|
||||
|
||||
enum UserRole {
|
||||
CLIENT
|
||||
MANAGER
|
||||
}
|
||||
|
||||
enum MessengerType {
|
||||
TELEGRAM
|
||||
MAX
|
||||
}
|
||||
|
||||
enum RegistrationStatus {
|
||||
PENDING
|
||||
APPROVED
|
||||
REJECTED
|
||||
}
|
||||
|
||||
enum OrderKind {
|
||||
READY
|
||||
CALCULATION
|
||||
}
|
||||
|
||||
enum OrderStatus {
|
||||
NEW
|
||||
MANAGER_PROCESSING
|
||||
WAITING_DOUBLE_CONFIRM
|
||||
CLIENT_REJECTED
|
||||
MANAGER_REJECTED
|
||||
MANAGER_BLOCKED
|
||||
CONFIRMED
|
||||
IN_PROGRESS
|
||||
COMPLETED
|
||||
}
|
||||
|
||||
enum WithdrawalStatus {
|
||||
PENDING
|
||||
APPROVED
|
||||
REJECTED
|
||||
}
|
||||
|
||||
enum Decision {
|
||||
APPROVE
|
||||
REJECT
|
||||
}
|
||||
|
||||
type Company {
|
||||
id: ID!
|
||||
name: String!
|
||||
inn: String
|
||||
}
|
||||
|
||||
type User {
|
||||
id: ID!
|
||||
email: String!
|
||||
fullName: String!
|
||||
role: UserRole!
|
||||
company: Company
|
||||
}
|
||||
|
||||
type Invitation {
|
||||
id: ID!
|
||||
token: String!
|
||||
email: String!
|
||||
companyName: String!
|
||||
managerId: ID!
|
||||
acceptedById: ID
|
||||
expiresAt: DateTime!
|
||||
acceptedAt: DateTime
|
||||
createdAt: DateTime!
|
||||
}
|
||||
|
||||
type RegistrationRequest {
|
||||
id: ID!
|
||||
companyName: String!
|
||||
inn: String
|
||||
contactName: String!
|
||||
email: String!
|
||||
status: RegistrationStatus!
|
||||
rejectionReason: String
|
||||
reviewedById: ID
|
||||
createdAt: DateTime!
|
||||
updatedAt: DateTime!
|
||||
}
|
||||
|
||||
type MessengerConnection {
|
||||
id: ID!
|
||||
userId: ID!
|
||||
type: MessengerType!
|
||||
channelId: String!
|
||||
isActive: Boolean!
|
||||
}
|
||||
|
||||
type Warehouse {
|
||||
id: ID!
|
||||
code: String!
|
||||
name: String!
|
||||
}
|
||||
|
||||
type ProductWarehouseBalance {
|
||||
warehouse: Warehouse!
|
||||
availableQty: Float!
|
||||
}
|
||||
|
||||
type Product {
|
||||
id: ID!
|
||||
sku: String!
|
||||
name: String!
|
||||
description: String
|
||||
isCustomizable: Boolean!
|
||||
isActive: Boolean!
|
||||
availableInWarehouses: [ProductWarehouseBalance!]!
|
||||
}
|
||||
|
||||
type OrderItem {
|
||||
id: ID!
|
||||
productId: ID
|
||||
productName: String!
|
||||
quantity: Float!
|
||||
}
|
||||
|
||||
type OrderStatusEvent {
|
||||
id: ID!
|
||||
status: OrderStatus!
|
||||
actorUserId: ID!
|
||||
note: String
|
||||
createdAt: DateTime!
|
||||
}
|
||||
|
||||
type Order {
|
||||
id: ID!
|
||||
code: String!
|
||||
kind: OrderKind!
|
||||
status: OrderStatus!
|
||||
customerId: ID!
|
||||
managerId: ID
|
||||
clientApproved: Boolean
|
||||
managerApproved: Boolean
|
||||
blockReason: String
|
||||
deliveryTerms: String
|
||||
deliveryFee: Float
|
||||
totalPrice: Float
|
||||
calculationPayload: JSON
|
||||
items: [OrderItem!]!
|
||||
history: [OrderStatusEvent!]!
|
||||
createdAt: DateTime!
|
||||
updatedAt: DateTime!
|
||||
}
|
||||
|
||||
type ReferralLink {
|
||||
id: ID!
|
||||
referrerId: ID!
|
||||
refereeId: ID!
|
||||
createdAt: DateTime!
|
||||
}
|
||||
|
||||
type BonusTransaction {
|
||||
id: ID!
|
||||
userId: ID!
|
||||
amount: Float!
|
||||
reason: String!
|
||||
orderId: ID
|
||||
createdAt: DateTime!
|
||||
}
|
||||
|
||||
type RewardWithdrawalRequest {
|
||||
id: ID!
|
||||
requesterId: ID!
|
||||
amount: Float!
|
||||
status: WithdrawalStatus!
|
||||
reviewedById: ID
|
||||
reviewComment: String
|
||||
createdAt: DateTime!
|
||||
updatedAt: DateTime!
|
||||
}
|
||||
|
||||
type ReferralStats {
|
||||
referrerId: ID!
|
||||
availableBalance: Float!
|
||||
referralsCount: Int!
|
||||
transactions: [BonusTransaction!]!
|
||||
pendingWithdrawals: [RewardWithdrawalRequest!]!
|
||||
}
|
||||
|
||||
type Query {
|
||||
healthcheck: String!
|
||||
me: User
|
||||
clientProducts: [Product!]!
|
||||
myOrders: [Order!]!
|
||||
myCurrentOrders: [Order!]!
|
||||
managerOrders(status: OrderStatus): [Order!]!
|
||||
registrationRequests(status: RegistrationStatus): [RegistrationRequest!]!
|
||||
referralStats: ReferralStats!
|
||||
}
|
||||
|
||||
input RegisterSelfInput {
|
||||
companyName: String!
|
||||
inn: String
|
||||
contactName: String!
|
||||
email: String!
|
||||
}
|
||||
|
||||
input ReviewRegistrationRequestInput {
|
||||
requestId: ID!
|
||||
decision: Decision!
|
||||
rejectionReason: String
|
||||
}
|
||||
|
||||
input CreateInvitationInput {
|
||||
email: String!
|
||||
companyName: String!
|
||||
expiresInDays: Int = 7
|
||||
}
|
||||
|
||||
input AcceptInvitationInput {
|
||||
token: String!
|
||||
fullName: String!
|
||||
}
|
||||
|
||||
input ConnectMessengerInput {
|
||||
type: MessengerType!
|
||||
channelId: String!
|
||||
}
|
||||
|
||||
input ReadyOrderItemInput {
|
||||
productId: ID!
|
||||
quantity: Float!
|
||||
}
|
||||
|
||||
input SubmitReadyOrderInput {
|
||||
items: [ReadyOrderItemInput!]!
|
||||
}
|
||||
|
||||
input SubmitCalculationOrderInput {
|
||||
productName: String!
|
||||
quantity: Float!
|
||||
parameters: JSON!
|
||||
}
|
||||
|
||||
input SetOrderOfferInput {
|
||||
orderId: ID!
|
||||
deliveryTerms: String!
|
||||
deliveryFee: Float!
|
||||
totalPrice: Float!
|
||||
}
|
||||
|
||||
input BlockOrderInput {
|
||||
orderId: ID!
|
||||
reason: String!
|
||||
}
|
||||
|
||||
input CreateReferralInput {
|
||||
refereeUserId: ID!
|
||||
}
|
||||
|
||||
input AddBonusTransactionInput {
|
||||
userId: ID!
|
||||
amount: Float!
|
||||
reason: String!
|
||||
orderId: ID
|
||||
}
|
||||
|
||||
input RequestRewardWithdrawalInput {
|
||||
amount: Float!
|
||||
}
|
||||
|
||||
input ReviewRewardWithdrawalInput {
|
||||
withdrawalId: ID!
|
||||
decision: Decision!
|
||||
reviewComment: String
|
||||
}
|
||||
|
||||
type Mutation {
|
||||
registerSelf(input: RegisterSelfInput!): RegistrationRequest!
|
||||
reviewRegistrationRequest(input: ReviewRegistrationRequestInput!): RegistrationRequest!
|
||||
createInvitation(input: CreateInvitationInput!): Invitation!
|
||||
acceptInvitation(input: AcceptInvitationInput!): User!
|
||||
connectMessenger(input: ConnectMessengerInput!): MessengerConnection!
|
||||
|
||||
submitReadyOrder(input: SubmitReadyOrderInput!): Order!
|
||||
submitCalculationOrder(input: SubmitCalculationOrderInput!): Order!
|
||||
managerSetOrderOffer(input: SetOrderOfferInput!): Order!
|
||||
clientReviewOrder(orderId: ID!, decision: Decision!): Order!
|
||||
managerFinalizeOrder(orderId: ID!, decision: Decision!): Order!
|
||||
blockOrder(input: BlockOrderInput!): Order!
|
||||
startOrderWork(orderId: ID!): Order!
|
||||
completeOrder(orderId: ID!): Order!
|
||||
|
||||
createReferral(input: CreateReferralInput!): ReferralLink!
|
||||
addBonusTransaction(input: AddBonusTransactionInput!): BonusTransaction!
|
||||
requestRewardWithdrawal(input: RequestRewardWithdrawalInput!): RewardWithdrawalRequest!
|
||||
reviewRewardWithdrawal(input: ReviewRewardWithdrawalInput!): RewardWithdrawalRequest!
|
||||
}
|
||||
23
nuxt.config.ts
Normal file
23
nuxt.config.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
// https://nuxt.com/docs/api/configuration/nuxt-config
|
||||
export default defineNuxtConfig({
|
||||
compatibilityDate: '2025-07-15',
|
||||
devtools: { enabled: true },
|
||||
modules: ['@nuxt/eslint', '@nuxtjs/tailwindcss'],
|
||||
css: ['~/assets/css/main.css'],
|
||||
runtimeConfig: {
|
||||
public: {
|
||||
graphqlEndpoint: process.env.NUXT_PUBLIC_GRAPHQL_ENDPOINT ?? 'http://localhost:4000/graphql',
|
||||
sentryDsn: process.env.NUXT_PUBLIC_SENTRY_DSN ?? '',
|
||||
sentryEnvironment: process.env.NUXT_PUBLIC_SENTRY_ENVIRONMENT ?? 'development',
|
||||
sentryRelease: process.env.NUXT_PUBLIC_SENTRY_RELEASE ?? 'dev',
|
||||
},
|
||||
},
|
||||
app: {
|
||||
head: {
|
||||
title: 'Fregat Client Cabinet',
|
||||
meta: [
|
||||
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
38
package.json
Normal file
38
package.json
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "nuxt-app",
|
||||
"type": "module",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "nuxt build",
|
||||
"dev": "nuxt dev",
|
||||
"generate": "nuxt generate",
|
||||
"preview": "nuxt preview",
|
||||
"postinstall": "nuxt prepare",
|
||||
"codegen": "graphql-codegen --config codegen.ts",
|
||||
"storybook": "storybook dev -p 6006",
|
||||
"build-storybook": "storybook build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.14.1",
|
||||
"@nuxt/eslint": "1.15.2",
|
||||
"@nuxtjs/tailwindcss": "6.14.0",
|
||||
"@sentry/vue": "^10.46.0",
|
||||
"@vue/apollo-composable": "^4.2.2",
|
||||
"daisyui": "^5.5.19",
|
||||
"graphql": "^16.13.2",
|
||||
"nuxt": "^4.4.2",
|
||||
"vue": "^3.5.30",
|
||||
"vue-router": "^5.0.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@graphql-codegen/cli": "^6.2.1",
|
||||
"@graphql-codegen/typed-document-node": "^6.1.7",
|
||||
"@graphql-codegen/typescript": "^5.0.9",
|
||||
"@graphql-codegen/typescript-operations": "^5.0.9",
|
||||
"@graphql-codegen/typescript-vue-apollo": "^5.0.0",
|
||||
"@storybook/addon-essentials": "8.6.14",
|
||||
"@storybook/vue3-vite": "^8.6.14",
|
||||
"storybook": "^8.6.14",
|
||||
"typescript": "5.9.2"
|
||||
}
|
||||
}
|
||||
12726
pnpm-lock.yaml
generated
Normal file
12726
pnpm-lock.yaml
generated
Normal file
File diff suppressed because it is too large
Load Diff
BIN
public/favicon.ico
Normal file
BIN
public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
2
public/robots.txt
Normal file
2
public/robots.txt
Normal file
@@ -0,0 +1,2 @@
|
||||
User-Agent: *
|
||||
Disallow:
|
||||
17
tailwind.config.ts
Normal file
17
tailwind.config.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import type { Config } from 'tailwindcss';
|
||||
import daisyui from 'daisyui';
|
||||
|
||||
export default {
|
||||
content: [
|
||||
'./app/**/*.{vue,ts,js}',
|
||||
'./components/**/*.{vue,ts,js}',
|
||||
'./pages/**/*.vue',
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [daisyui],
|
||||
daisyui: {
|
||||
themes: ['light', 'corporate'],
|
||||
},
|
||||
} satisfies Config;
|
||||
18
tsconfig.json
Normal file
18
tsconfig.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
// https://nuxt.com/docs/guide/concepts/typescript
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./.nuxt/tsconfig.app.json"
|
||||
},
|
||||
{
|
||||
"path": "./.nuxt/tsconfig.server.json"
|
||||
},
|
||||
{
|
||||
"path": "./.nuxt/tsconfig.shared.json"
|
||||
},
|
||||
{
|
||||
"path": "./.nuxt/tsconfig.node.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user